Вопросик из области Web-Programmierung, Java
Проблема такая. Пользователи открывают окно веб-приложения, залогиниваются и работают.
Второе окно открывать запрещено, но по какой-то причине оно все же открывается, пользователи заходят под другим логином, чтобы валидировать данные, введенные или измененные в первом окне (это может делать только другой пользователь, 4-Augen-Prinzip). В результате данные портятся. Так что моя задача - предотвратить открытие второго окна.
А вот третье окно открыть уже не удается, тут проверка почему-то срабатывает. Проверяется собсна наличие аплета:
if (Current- -Context.getMain- -() != null) (и если не налл, то следующее окно не открывается)
Это проверка делается в начале методы init() в классе Main- -(). В конце этой методы делается set:
Current- -Context.setMain- -(this);
Я сравниваю логи, полученные для первого окна и для второго, разницы почти никакой. Set в обоих случаях происходит. Так почему в первом случае оно не работает, а во втором работает? Есть у кого-нибудь какая-нибудь идея, может, сталкивались с таким ?
Работает оно все при посредстве Томката, аплет вызывается из сервлета.
"Thread-7" prio=4 tid=0x0c562400 nid=0x1f38 waiting on condition [0x0cd0f000]
java.lang.Thread.State: TIMED_WAITING (sleeping)
Во втором:
"Thread-7" prio=4 tid=0x0b6c1400 nid=0x1210 runnable [0x0c68f000]
java.lang.Thread.State: RUNNABLE
------
В контексте - Web-Programmierung - никак - там не регламентировано какие клиенты могут заходить.
Там вообще может не быть <HTTP>-клиента, а трафик на сервер может формировать <TELNET>.
В результате данные портятся.
-----
Значит построение всего приложения не соответствует заявленному Web-Programmierung.
В Вебе каждый запрос к серверу должен работать как отдельная транзакция, все операции на клиенте должны выполнятся в пределах загружаемой <HTML>страницы. Штучки типa откроем рядышком вторую форму - от лукавого...
почему в первом случае оно не работает, а во втором работает?
-----
Потому как <Java> и <Java S Cript> совершенно разные и работают на разных хостах - <Java> - на сервере, исключая загружаемый на клиента класс, <Java S Cript> - на клиенте, если не указано что используется серверный скрипт.
Значит построение всего приложения не соответствует заявленному Web-Programmierung.
Вероятно, так и есть, но я не могу переписывать заново все приложение.
Проблема в том, что и в первом, и во втором окне - одна и та же сессия, эта сессия привязана только к IP компутера.
В результате второй юзер портит то, что делает первый, и наоборот, т.к. ряд переменных действительны для всей сессии.
почему в первом случае оно не работает, а во втором работает?
-----
Потому как <Java> и <Java S Cript> совершенно разные и работают на разных хостах - <Java> - на сервере, исключая загружаемый на клиента класс, <Java S Cript> - на клиенте, если не указано что используется серверный скрипт.
Честно говоря, не понял, я совершенно не продвинут в этом плане. Java S Cript - это JavaSсript, как я понимаю?
А при чем тут яваскрипт, у меня нет там никаких яваскриптов?
И чо делать??
-----
Ну и чем же тебе помочь?
Пойми элементарное - веб-пользователь, по определению, может запустить любое количество любых клиентов.
Даже если ты заблокируешь открытие окна по нажатию какого-то кнопарика на форме, то ничто не мешает юзеру запустить другой бровсер и набить нужный <URL>...
И чо делать??
-----
Просто разобраться на какой машине какой код выполняется. Потому как они физически разные.
По приложению. Лет 15-ть назад Я делал что-то похожее, со сложной навигацией по формам.
Решение было: ввести два канала - данные отдельно и управление отдельно, перехватывать все на входе
и оценивать ситуацию. Но это - долго и не просто. Но работает - замечатерльно.
у меня нет там никаких яваскриптов?
-----
Не знаю. Надо смотреть что и как у тебя сделано. Спроси у спецов по <Java+TomCat> как они с этим живут.
как я понимаю?
-----
Да, у меня просто нет русского на клаве...
Пойми элементарное - веб-пользователь, по определению, может запустить любое количество любых клиентов.
В том-то и дело, что нет!
Еще раз: третье окно успешно блокируется!
Второе - нет, и в этом вся проблема...
Даже если ты заблокируешь открытие окна по нажатию какого-то кнопарика на форме, то ничто не мешает юзеру запустить другой бровсер и набить нужный <URL>...
См. выше.
Просто разобраться на какой машине какой код выполняется. Потому как они физически разные.
Не понял, о каких машинах речь?
Еще раз, пойми: апплет запускается из сервлета.
Он успешно регистрируется и первый раз, и второй. Второй раз это помогает.
Первый - нет. Я предполагаю, что каким-то образом умирает сам сервлет или первый аплет теряется каким-то другим образом.
Решение было: ввести два канала - данные отдельно и управление отдельно, перехватывать все на входе
и оценивать ситуацию. Но это - долго и не просто. Но работает - замечатерльно.
Это было бы отличным решением, но у меня нет задачи переписывать заново весь код и нет времени на это. Сегодня у меня последний срок

Не знаю. Надо смотреть что и как у тебя сделано. Спроси у спецов по <Java+TomCat> как они с этим живут
Ну, вот же я и спрашиваю...
Например - браузер для большей скорости держит два процесса JVM. Апплет в первом окне запускается в 1-м процессе, апплет второго - во втором, апплет третьего - снова в первом. Каждый аплет может (вообще говоря должен) грузится в своем Classloader-е. Тогда опять же у каждого свой вариант класса со своим значением статической переменной будет.
Но оно и не важно, потому что в крайнем случае если пользователь запустит два браузера, кадый запустит свою JVM, у каждого будет своя копия CurrentContext.
Так делать нельзя и это не исправить, только переделывать. Апплет по-хорошему не должен вылазить за свою песочницу (окно браузера).
Проверяйте на сервере есть ли уже сессия для этого же IP. Кстати, привязывать сессии к IP-адресу тоже глупо. А что делать юзерам за NAT-ом? По очереди работать? У вас же пользователи логинятся, ну так и привязывайте сессии к залогиненному пользователю.
------
Ну хорошо: <ИЕ>, <Chrome>, <Opera>, <Mozilla> - запускаем по одной сессии и начинаем блокировать? Что именно будем блокировать? Кто тебя пустит с <IE> в <Chrome>? Ну а раз НЕ идет - нефиг и заморачиваться.
Я предполагаю, что каким-то образом умирает сам сервлет или первый аплет теряется каким-то другим образом.
-----
Серверный процесс генерации <HTML> (ничего другого в рамках Веб-программирования не используется) не существует по окончании генерации <HTML>-документа. Все, что делается "якобы по-другому" - пляски с бубном вокруг уже помершего и пересозданного процесса, со складированием информации на сервере или получением ее же с клиента.
<Java-- ->ы встроенные в <HTML>-документы - это отдельные серверные процессы. Как они работают в целом Я представляю, но в деталях не разбирался - нужно либо смотреть самому, либо уточнять у того кто знает.
Но суть останется та же - сервер сгенерил <HTML>-документ, отдал его клиенту и забыл про процесс.
Клиент, получив <HTML>, рендрит его в соответствии со своими правилами, подтягивая отсутствующие элементы - картинки, обьэкты, апплеты и т.п.
И совсем не обязательно, что контент будет с того же сервера.
Ну, вот же я и спрашиваю...
-----
Увы, но с <Java> Я последний раз работал лет 7-8 назад, а с <JSP> - еще до 2000-го - что-то базовое - да сделаю, но глубокие нюансы - увы, не мое...
Например - браузер для большей скорости держит два процесса JVM.
А как это можно предотвратить?
Апплет в первом окне запускается в 1-м процессе, апплет второго - во втором, апплет третьего - снова в первом. Каждый аплет может (вообще говоря должен) грузится в своем Classloader-е. Тогда опять же у каждого свой вариант класса со своим значением статической переменной будет.
Но оно и не важно, потому что в крайнем случае если пользователь запустит два браузера, кадый запустит свою JVM, у каждого будет своя копия CurrentContext.
Вот что-то такое у меня в голове и крутится...
Важное уточнение: для первого окна открывается Java Console, для второго тоже открывается своя, вторая Java Console.
В третьем окне своя консоль уже не открывается.
Вопрос: а к чему привязана консоль? К каждому отдельному апплету, сервлету или чему?
Но оно и не важно, потому что в крайнем случае если пользователь запустит два браузера, кадый запустит свою JVM, у каждого будет своя копия CurrentContext.
Два браузера - это два разных типа браузера или просто две разных инстанции?
Если первое, то не страшно, у нас официально разрешен только один браузер.
Так делать нельзя и это не исправить, только переделывать. Апплет по-хорошему не должен вылазить за свою песочницу (окно браузера).
Проверяйте на сервере есть ли уже сессия для этого же IP.
Есть! Я об этом уже написал. Сессия одна и та же. Даже если юзер вечером закроет браузер, а утром откроет новый (не удалив к черту все куки и прочее дерьмо), то это будет все та же сессия, видно по логам

И в этом проблема. А как сделать, чтобы сессия обновлялась?
Привязать к LogOffу нельзя, юзер может просто закрыть браузер, так все и делают.
Кстати, привязывать сессии к IP-адресу тоже глупо. А что делать юзерам за NAT-ом? По очереди работать? У вас же пользователи логинятся, ну так и привязывайте сессии к залогиненному пользователю.
Так не получается. Сессия создается ДО логина.
Схема такая: стартует сервлет (StartsServer), потом иницируется апплет (init()), только потом делается логин...
Я пока что испробовал еще два варианта: создавать флаг, что один апплет уже существует и второй нельзя, не в CurrentContext, а в самом классе, и потом еще более серьезная проверка: создаю этот флаг в самом сервлете (StartsServer). Результат, как ни странно, один и тот же: второе окно создается, третье - нет..
Ну хорошо: <ИЕ>, <Chrome>, <Opera>, <Mozilla> - запускаем по одной сессии и начинаем блокировать? Что именно будем блокировать? Кто тебя пустит с <IE> в <Chrome>? Ну а раз НЕ идет - нефиг и заморачиваться.
У нас разрешен только ИЕ. Чтобы каким-то образом скачать другие, надо очень постараться. Я лично знаю только один способ: скачать дома и послать по почте, переименовав в текстовый. Иначе не дойдет. Чтобы самому инсталлировать, тоже нужны ухищрения, потому что права сильно обрезаны.
Серверный процесс генерации <HTML> (ничего другого в рамках Веб-программирования не используется) не существует по окончании генерации <HTML>-документа. Все, что делается "якобы по-другому" - пляски с бубном вокруг уже помершего и пересозданного процесса, со складированием информации на сервере или получением ее же с клиента.
<Java-- ->ы встроенные в <HTML>-документы - это отдельные серверные процессы. Как они работают в целом Я представляю, но в деталях не разбирался - нужно либо смотреть самому, либо уточнять у того кто знает.
Но суть останется та же - сервер сгенерил <HTML>-документ, отдал его клиенту и забыл про процесс.
А вот и нет!
Я встроил проверку наличия аплета в запускающий сервлет (см. выше).
Проверка работает! но только для третьего окна.
------
Никак.
это два разных типа браузера или просто две разных инстанции?
-----
Почти без разницы.
А как сделать, чтобы сессия обновлялась?
------
Настроить <timeout> для сессий.
а в самом классе
-----
В другой машине у тебя будет не только другой инстансе класса, но и другой набор статиц-переменных. Тебе об этом уже писали.
чему привязана консоль?
------
Консоль есть отдельный изолированный процесс в системе.
------
Ну нет так нет.
Обрежь на файрволе все кроме 80 порта и запиши весь трафик - там все понятно будет.
У нас разрешен только ИЕ.
------
Ну так запусти по <AT> вторую копию с правами другого юзера и попробуй из первого прибить запущенный оттуда процесс... Если сможешь - работать тебе больше не надо будет - все вирусописатели у тебя технологию купят...

Настроить <timeout> для сессий.
А где это настраивается?
Обрежь на файрволе все кроме 80 порта и запиши весь трафик - там все понятно будет.
У меня прав таких нет.
Ну так запусти по <AT> вторую копию с правами другого юзера и попробуй из первого прибить запущенный оттуда процесс...
У меня только один юзер. А что такое АТ?
Я вот размышляю: если это две JVM в IE, то, может, в Мозилле попробовать (проверить хотя бы).
Скачал java plugin для Мозиллы, но комп пока не перезапустил.
------
Где-то в <TomCat>е. Где именно - Я не знаю.
У меня прав таких нет.
------
У тебя нет прав на твоей машине? Или все от компании?
А что такое АТ?
------
Команда консоли для установки времени и/или периодичности запуска других команд с определенными привелегиями.
java plugin для Мозиллы
------
Пыххх... <Java> машин было две - от мелкомягких и от САН. Браузер пользует ту машину которая установлена в системе.
Где-то в <TomCat>е. Где именно - Я не знаю.
А это точно что-то даст?
Если пользователь решит запустить два окна, то никакой тайм аут не поможет. Или я ошибаюсь?
У тебя нет прав на твоей машине?
Нету

Пыххх... <Java> машин было две - от мелкомягких и от САН. Браузер пользует ту машину которая установлена в системе.
Мне нужен только плагин для Мозиллы.
-----
Ты пожаловался на то, что у тебя не умирают сессии. Для того, чтобы они умирали после некоторой неактивности пользователя настраивается <timeout> для сессии. Нужно это тебе или нет - никто кроме тебя не знает.
Мой опыт говорит, что сессии должны помирать. В противном случае в них накапливается мусор и иногда он просто роняет сервер.
Если пользователь решит запустить два окна, то никакой тайм аут не поможет.
-----
Разумеется нет. Это механизм для других целей.
От компании.
-----
Увы и ах... Тащи собственный лапоть и тести на нем...
Мне нужен только плагин для Мозиллы.
------
Кажется ты очень далек от понимания ситуации. <Java> это не только язык, но еще и среда выполнения байт-кода называемая Виртуальной Жаба Машиной <JVM>. Какие мостики/плагины к ней пристраиваются - не суть важно. Важно, что машин по крайней мере две и что они существенно - т.е. до уровня неработоспособности кода/технологий - разные. То, что у тебя глючит при использовании мелкософтовской машины, может не иметь проблем в сановской. И наоборот. Правда так было довольно давно. Как сейчас - не знаю.
Разумеется нет. Это механизм для других целей.
О том и речь. Другая проблема передо мной не стоит
Увы и ах... Тащи собственный лапоть и тести на нем..
Не дают.
<Java> это не только язык, но еще и среда выполнения байт-кода называемая Виртуальной Жаба Машиной <JVM>. Какие мостики/плагины к ней пристраиваются - не суть важно. Важно, что машин по крайней мере две и что они существенно - т.е. до уровня неработоспособности кода/технологий - разные. То, что у тебя глючит при использовании мелкософтовской машины, может не иметь проблем в сановской. И наоборот. Правда так было довольно давно. Как сейчас - не знаю.
Может не иметь, а может и иметь. Товарисч выше написал, что браузер может использовать две машины для двух окон, а третье запускать снова в первой машине. Вот это я и хочу проверить.
.. запустить два разных инстанса одной и той же <JVM>. Может и больше...
Плюс, он так же написал что именно неправильно в том что имеется... но
понять что именно написано ты не хочешь...
По-моему, это ты не хочешь. Именно об этом я и говорю.
Базар про разные Ява-машины ты начал, не я. Если дело в установках браузера, то Мозилла, возможно, не будет запускать две ява-машинки, и тогда я хоть пойму, в чем причина.
потому и разные названия
обе программы- пакет снифферы, позволяют записать и визуализировать процесс обмена пакетами между клиентом и сервером
я подозреваю, что ты там не один единственный воин, кто этим занимается, есть и сетевые админы.
они могут по просьбе стартануть одновременно вышеупомянутые программы, записать дампы и помочь эти дампы проанализировать
дампы покажут, как идет обмен пакетами. что делает клиент, что в ответ делает сервер, какое окно явлется чьим чилдом и кто является чьим парентом.
в таком аксепте..
А как это можно предотвратить?
Настройками браузера. Читай - никак. Ещё раз, копая в эту сторону вы решения не найдёте.
Важное уточнение: для первого окна открывается Java Console, для второго тоже открывается своя, вторая Java Console.
В третьем окне своя консоль уже не открывается.
Вопрос: а к чему привязана консоль?
Хех, похоже я угадал. Обычно консоль запускается для запущенной JVM
Два браузера - это два разных типа браузера или просто две разных инстанции?
Просто два процесса одного браузера.
то это будет все та же сессия, видно по логам
Сессия создается ДО логина
Вы меня запутали. Что вы называете сессией? HttpSession или что-то своё, что вы контролируетее сами?
Схема такая: стартует сервлет (StartsServer)
Когда он стартует?
При запуске веб-сервера или при вызове doGet() или doPost()?
создавать флаг, что один апплет уже существует и второй нельзя, не в CurrentContext, а в самом классе
Нет разницы
создаю этот флаг в самом сервлете (StartsServer)
А вот тут вы что-то делаете неправильно. У сервлета (у вас) должна быть одна копия (вы же не запускаете его на нескольких машинах за LoadBalancer-ом)
Покажите код сервлета
что делает клиент, что в ответ делает сервер, какое окно явлется чьим чилдом и кто является чьим парентом.
в таком аксепте
Не имеет смысла. Ну увидит ТС что от двух разных JVM пакеты идут. А может и не увидеть. Можно и внутри одной машины апплеты изолировать. Что это ему даст? Ничего нового. Реализованая логика - контроль на стороне клиента - неверна, работать может только случайно.
может быть, что-то можно будет и увидеть. как-то же они разрабатывали это приложение? при разработке же использовался какой-то дебаггер?
в моей работе тспдамп помогает здорово, по-крайней мере, нам удается без проблем отделять нетворк релейтед ишью от не нетворк релейтед ван.
хорошо удается различить траффик, приходящий от разных тиров, и уходящий к разным тирам- сиквел, аппликейшн и прочее, и видно, что является причиной, а что- следствием.
думаю, что если такая ситуация- то не будет проблемы попробовать- костет зовизо никс.
костет зовизо никс.
Ну да, по деньгам не стоит. По времени - с wireshark-ом разобраться не так просто. Если есть время и желание, то, конечно, не помешает. Но для данной конкретной ошибки и не даст ничего. Чесслово. Потому как она вообще без привязки к сети происходит. ТС пытается в апплете определить бегает ли вторая копия такого же апплета на этой же машине. А это возможно только если позволить апплету, вылезать из своей песочницы, например, менять переменные среды. Или писать в файл. "Средствами системы невозможно определить покоится ли система или движется равномерно и прямолинейно" (с)
сервер, подозреваю- линукс машина, клиент- виндоус
Tomcat Apache на Солярке (Юниксе, даже хуже того - AIX).
обе программы- пакет снифферы, позволяют записать и визуализировать процесс обмена пакетами между клиентом и сервером
я подозреваю, что ты там не один единственный воин, кто этим занимается, есть и сетевые админы.
они могут по просьбе стартануть одновременно вышеупомянутые программы, записать дампы и помочь эти дампы проанализировать
дампы покажут, как идет обмен пакетами. что делает клиент, что в ответ делает сервер, какое окно явлется чьим чилдом и кто является чьим парентом.
в таком аксепте..
Понял, спасибо. Хрен знает, я с админами не общаюсь, они и сидят-то далеко.
В ответ на:
--------------------------------------------------------------------------------
костет зовизо никс.
Ну да, по деньгам не стоит. По времени - с wireshark-ом разобраться не так просто. Если есть время и желание, то, конечно, не помешает. Но для данной конкретной ошибки и не даст ничего. Чесслово.
чтобы запустить тспдамп нужно будет открывать тикет у сетевиков/админов этого соляриса, а цветы и конфеты админы, как известно, не пьют.
зато, эти же самые админы помогут и получившиеся дампы проанализировать.
Потому как она вообще без привязки к сети происходит. ТС пытается в апплете определить бегает ли вторая копия такого же апплета на этой же машине. А это возможно только если позволить апплету, вылезать из своей песочницы, например, менять переменные среды. Или писать в файл. "Средствами системы невозможно определить покоится ли система или движется равномерно и прямолинейно" (с)
А как это можно предотвратить?
Настройками браузера. Читай - никак. Ещё раз, копая в эту сторону вы решения не найдёте.
Решения, конечно, нет, я лишь хотел удостовериться, что дело именно в двух Ява-машинах.
А пока я и причины не знаю, трудно что-то лечить.
Вы меня запутали. Что вы называете сессией? HttpSession или что-то своё, что вы контролируетее сами?
Сессия - это.. сессия!

В принципе можно вообще работать, не залогиниваясь (при отключенной секьюрити), что мы часто и делаем. Вы же не будете говорить, что в этом случае нет никакой сессии?
Ну, вот кусочек лога:
01.09.2015 12:27:23 DCC_4 (25) I: >>>> Start of external request (getClientParamForMandant) - id (25)
01.09.2015 12:27:23 DCC_4 (25) I: prepareForRequest <25>
01.09.2015 12:27:23 DCC_4 (25) I: request for access key: 540C407B5B9122D19AFC1588C2A49579
01.09.2015 12:27:23 DCC_4 (PP_AuthenticationServer) I: getMandantFor: 540C407B5B9122D19AFC1588C2A49579
Вот этот код - 540C407B5B9122D19AFC1588C2A49579 - это и есть идентификатор сессии, и он остается неизменным для разных окон.
При залогинивании и перелогинивании он, естественно, тоже не меняется.
Когда он стартует?
При запуске веб-сервера или при вызове doGet() или doPost()?
Второе.
Дебаггер у меня есть, в Эклипсе, но в данном случае от него мало проку, дебаггить я могу только апплет, запускаемый в Эклипсе, а не в браузере.
Код сервлета прилагаю.
А как это можно предотвратить?
Настройками браузера. Читай - никак. Ещё раз, копая в эту сторону вы решения не найдёте.
Решения, конечно, нет, я лишь хотел удостовериться, что дело именно в двух Ява-машинах.
А пока я и причины не знаю, трудно что-то лечить.
Вы меня запутали. Что вы называете сессией? HttpSession или что-то своё, что вы контролируетее сами?
Сессия - это.. сессия!

В принципе можно вообще работать, не залогиниваясь (при отключенной секьюрити), что мы часто и делаем. Вы же не будете говорить, что в этом случае нет никакой сессии?
Ну, вот кусочек лога:
01.09.2015 12:27:23 DCC_4 (25) I: >>>> Start of external request (getClientParamForMandant) - id (25)
01.09.2015 12:27:23 DCC_4 (25) I: prepareForRequest <25>
01.09.2015 12:27:23 DCC_4 (25) I: request for access key: 540C407B5B9122D19AFC1588C2A49579
01.09.2015 12:27:23 DCC_4 (PP_AuthenticationServer) I: getMandantFor: 540C407B5B9122D19AFC1588C2A49579
Вот этот код - 540C407B5B9122D19AFC1588C2A49579 - это и есть идентификатор сессии, и он остается неизменным для разных окон.
При залогинивании и перелогинивании он, естественно, тоже не меняется.
Когда он стартует?
При запуске веб-сервера или при вызове doGet() или doPost()?
Второе.
Дебаггер у меня есть, в Эклипсе, но в данном случае от него мало проку, дебаггить я могу только апплет, запускаемый в Эклипсе, а не в браузере.
Код сервлета прилагаю. Последние сеттер и геттер - это уже мои сегодняшние художества.
------
Нее, не поймешь. Потому как это не Мозилла вс ИЕ, а МС <JVM> вс САН <JVM>. Ну и плюс конфигурация <JVM>.
Но даже если если разберешься в чем разница - тебе оно, кроме как для понимания ситуации, безполезно.
Как же его прицепить-то?
Ну, ладно, придется запостить так, не весь:
/**
* This classs initializes the RMI-Server.
*
* @author cirquent
* @version 1.86 31.07.2008
*/
public class StartServer
{
private static Properties c_argProperties = new Properties();
private final static String c_actualVersion = "9.5.0.1";
private static Main- - c_main- - = null;
// main routine for starting the rmi-server
public static void main(String[] args)
{
// LogConsole starts only if the parameter LogConsole is set to 1
// Set the LogConsoleX and LogConsoleY parameters for a specific position
// of the console on your screen
if ((System.getProperty("LogConsole")) != null && System.getProperty("LogConsole").equals("1"))
{
int iLogConsoleX=0;
int iLogConsoleY=0;
if (System.getProperty("LogConsoleX")!=null) iLogConsoleX=Integer.parseInt(System.getProperty("LogConsoleX"));
if (System.getProperty("LogConsoleY")!=null) iLogConsoleY=Integer.parseInt(System.getProperty("LogConsoleY"));
new LogConsole("Server",iLogConsoleX,iLogConsoleY);
}
String strHostName = "";
int iRMIPort = 1099; // default port of the rmiregistry
String strProduct = null;
String strInstanceNumber = null;
String temp;
// use DCC specific copy configuration
CopyConfiguration.loadConfiguration();
//In the Moment, we set no Security! It remains to check, if you can do it with policy-files
System.setSecurityManager(new RMISecurityManager());
// we have to set a virtual request name for the following requests
// (this is necessary for the current concept of reentrant database
// access)
Thread.currentThread().setName("StartServer");
// define that we are located on the server...
GeneralServerAdapter_RMI.setLocatedOnServer(true);
// show threadname in trace output on server side
Trace.setShowThreadName(true);
//parse the input parameters of the main-program
System.out.println ("Server " + c_actualVersion);
try
{
parseInputArgs (args);
}
catch (Exception e)
{
System.out.println ("Error in the input parameters");
System.out.println("Usage: java [vmargs] [package].StartServer -p <programname> -n <instancenr>");
System.out.println("The rmiserver-process was not started");
System.exit(-1);
}
//Show the System and Program Properties!
if (System.getProperty("properties.show") != null)
printProperties();
//parse the parameters of the vm
try
{
//product + instancenumber
strProduct = System.getProperty("product");
Assertion.verify(strProduct != null);
strInstanceNumber = System.getProperty("instance");
Assertion.verify(strInstanceNumber != null);
//set a prefix to the rmi-servername to distinguish different Servers
temp = strProduct + "_" + strInstanceNumber;
GeneralServer.setServerNamePrefix(temp + ".");
// we can set it globally because any instance of this adapter
// has to use this prefix...
GeneralServerAdapter.setGlobalServerNamePrefix(temp + ".");
Trace.setPrefix(temp);
// trace on/off?
if (System.getProperty("Trace") != null)
Trace.setTraceLevel(Integer.parseInt(System.getProperty("Trace")));
// 1. database parameters
// (the flag on calls to DBAccess-class decide for local (true) or
// central (false) database)
// a) local database
if (System.getProperty("db.server") != null)
DBAccess.setDBServer(System.getProperty("db.server"), true);
if (System.getProperty("db.database") != null)
{
temp = System.getProperty("db.database");
if (temp != null)
DBAccess.setDBName(temp, true);
}
if (System.getProperty("db.user") != null)
DBAccess.setDBUser(System.getProperty("db.user"), true);
if (System.getProperty("db.password") != null)
DBAccess.setDBPassword(System.getProperty("db.password"), true);
if (System.getProperty("db.url_param") != null) {
DBAccess.setDBAddParamAtUrl(System.getProperty("db.url_param"));
}
if (System.getProperty("db.jdbcurl") != null)
DBAccess.setDBURL(System.getProperty("db.jdbcurl"), true);
if (System.getProperty("db.host") != null)
DBAccess.setDBHost(System.getProperty("db.host"), true);
if (System.getProperty("db.port") != null)
DBAccess.setDBPort(System.getProperty("db.port"), true);
// b) central database
if (System.getProperty("dbc.server") != null)
DBAccess.setDBServer(System.getProperty("dbc.server"), false);
if (System.getProperty("dbc.database") != null)
{
temp = System.getProperty("dbc.database");
if (temp != null)
DBAccess.setDBName(temp, false);
}
if (System.getProperty("dbc.user") != null)
DBAccess.setDBUser(System.getProperty("dbc.user"), false);
if (System.getProperty("dbc.password") != null)
DBAccess.setDBPassword(System.getProperty("dbc.password"), false);
if (System.getProperty("dbc.jdbcurl") != null)
DBAccess.setDBURL(System.getProperty("dbc.jdbcurl"), false);
if (System.getProperty("dbc.host") != null)
DBAccess.setDBHost(System.getProperty("dbc.host"), false);
if (System.getProperty("dbc.port") != null)
DBAccess.setDBPort(System.getProperty("dbc.port"), false);
// 2. RMI-Server-Parameter
if (System.getProperty("rmi.host") != null)
{
temp = System.getProperty("rmi.host");
if (temp.indexOf(":") > 0)
{
//hostname contains rmi-port
strHostName = temp.substring(0, temp.indexOf(":"));
iRMIPort = Integer.parseInt(temp.substring(temp.indexOf(":")+1, temp.length()));
}
else
{
strHostName = temp;
iRMIPort = 1099; //default
}
//set the full hostname to the server and serverAdapter
GeneralServer.setHostName(strHostName);
GeneralServer.setRMIPort(iRMIPort);
GeneralServerAdapter.setHostName(strHostName);
GeneralServerAdapter.setRMIPort(iRMIPort);
}
//is a different path for NdCrypt set ? Position inc. filename
if (System.getProperty("CryptPath") !=null)
{
setCryptFilePath(System.getProperty("CryptPath"));
}
// activate security?
// this should be a unknown flag for the clients
if (System.getProperty("local.security") != null)
{
boolean fOn = (!System.getProperty("local.security").equals("0"));
Trace.traceInfo("Security enabled: " + fOn);
GeneralServer.setSecurityEnabled(fOn);
}
else
{
Trace.traceInfo("Security enabled: " + true);
GeneralServer.setSecurityEnabled(true);
}
if (GeneralServer.isSecurityEnabled())
{
// If security on, get Password from NdCrypt and inform DBAccess-class
// (password for local and central database)
DBAccess.setDBPassword(SecuritySupport.getPasswordProductDB(), true);
//DBAccess.setDBPassword("RevisionssicherheitICM6#", true);
// we only need the password for the central database in case it is
// different from the local database
if (!DBAccess.isLocalAndCentralDBIdentical())
DBAccess.setDBPassword(SecuritySupport.getPasswordCentralDB(), false);
}
// set a special time for automatic logoff ?
if (System.getProperty("logoffTime") != null)
{
AuthenticationServer.setAccessTimeExpiration(System.getProperty("logoffTime"));
}
String outFile = null;
if( (outFile = System.getProperty("sql.outfile")) != null)
{
try{
Trace.traceInfo("SQL commands are written to file: \'" + outFile + "\'");
if ( ! FileLogger.initLogFile( outFile, FileLogger.SQL_LOG ) )
{
throw new Exception ();
}
}
catch (Exception e)
{
System.out.println ("Error in opening sql outfile");
System.out.println("The rmiserver-process was not started");
System.exit(-1);
}
}
outFile = null;
if( (outFile = System.getProperty("sysmsg.outfile")) != null)
{
try{
Trace.traceInfo("System messages are written to file: \'" + outFile + "\'");
if ( ! FileLogger.initLogFile( outFile, FileLogger.SYSMSG_LOG ) )
{
throw new Exception ();
}
}
catch (Exception e)
{
System.out.println ("Error in opening system messages outfile");
System.out.println("The rmiserver-process was not started");
System.exit(-1);
}
}
// show automatic logoff time
AuthenticationServer.showAccessTimeExpiration();
// handle special parameters to modify server behaviour for performance
// (caching of result sets)
if (System.getProperty("perf.blocksize") != null)
DBAccess.setTransferBlockSize(Integer.parseInt(System.getProperty("perf.blocksize")));
if (System.getProperty("perf.expirationtime") != null)
DBAccess.setCacheEntryExpirationTime(Integer.parseInt(System.getProperty("perf.expirationtime")));
if (System.getProperty("perf.maxcachesize") != null)
DBAccess.setMaxCacheSize(Integer.parseInt(System.getProperty("perf.maxcachesize")));
if (System.getProperty("perf.maxresultsize") != null)
DBAccess.setMaxResultSetSize(Integer.parseInt(System.getProperty("perf.maxresultsize")));
DBAccess.showPerformanceParams();
// special parameter to set the maximum transfer blocksize for rmi-communication
if (System.getProperty("comm.transferblocksize") != null)
ndPersistenceServer.setMaxTransferBlockSize(Integer.parseInt(System.getProperty("comm.transferblocksize")));
if (System.getProperty("comm.transfercompression") != null)
ndPersistenceServer.setUseCompressionForTransfer(Integer.parseInt(System.getProperty("comm.transfercompression")) != 0);
if (System.getProperty("shell.timezone") != null)
CurrentDateSupport.setTimeSupport(System.getProperty("shell.timezone"));
Trace.traceInfo("set param -Dshell.timezone: " + CurrentDateSupport.getTimeSupport());
try
{
Registry reg = null;
// try to get a registry from given host
if (strHostName.length() > 0)
{
try
{
Trace.traceInfo("getRegistry: " + strHostName + " : " + iRMIPort);
reg = LocateRegistry.getRegistry(strHostName, iRMIPort);
// we have to contact the registry to check if it's really available
Assertion.verify(reg != null);
reg.list();
}
catch (Throwable e)
{
reg = null;
}
}
// try to get the registry on the current host
if (reg == null)
{
Trace.traceInfo("getRegistry : "+iRMIPort);
reg = LocateRegistry.getRegistry(iRMIPort);
// we have to contact the registry to check if it's really available
Assertion.verify(reg != null);
reg.list();
}
}
catch (Throwable e)
{
// if no registry was found - try to create one
Trace.traceInfo("createRegistry");
LocateRegistry.createRegistry(iRMIPort);
}
General- -.setServerForClass(ndDate.class, new ndDateServerAdapter_RMI());
General- -.setServerForClass(EventLog.class, new EventLogServerAdapter_RMI());
General- -.setServerForClass(dccEventLog.class, new dccEventLogServerAdapter_RMI());
General- -.setServerForClass(History.class, new HistoryServerAdapter_RMI());
General- -.setServerForClass(BackendAccess.class, new BackendAccessServerAdapter_RMI());
General- -.setServerForClass(Log.class, new LogServerAdapter_RMI());
General- -.setServerForClass(Currency.class, new CurrencyServerAdapter_RMI());
General- -.setServerForClass(DataManager.class, new DataManagerServerAdapter_RMI());
General- -.setServerForClass(Customer.class, new CustomerServerAdapter_RMI());
General- -.setServerForClass(DiAccount.class, new DiAccountServerAdapter_RMI());
General- -.setServerForClass(Settlement.class, new SettlementServerAdapter_RMI());
General- -.setServerForClass(DreCatiSettlement.class, new DreCatiSettlementServerAdapter_RMI());
General- -.setServerForClass(DreCatiCurrencyManager.class, new DreCatiCurrencyManagerServerAdapter_RMI());
General- -.setServerForClass(DreCatiAccount.class, new DreCatiAccountServerAdapter_RMI());
General- -.setServerForClass(DreCatiTrancheControl.class, new DreCatiTrancheControlServerAdapter_RMI());
General- -.setServerForClass(DccAccount.class, new DccAccountServerAdapter_RMI());
General- -.setServerForClass(User.class, new UserServerAdapter_RMI());
General- -.setServerForClass(LocalUser.class, new UserServerAdapter_RMI());
General- -.setServerForClass(Message.class, new MessageServerAdapter_RMI());
General- -.setServerForClass(ndMessage.class, new ndMessageServerAdapter_RMI());
General- -.setServerForClass(Authentication.class, new AuthenticationServerAdapter_RMI());
General- -.setServerForClass(MsgAccess.class, new MsgAccessServerAdapter_RMI());
General- -.setServerForClass(Program.class, new ProgramServerAdapter_RMI());
General- -.setServerForClass(ndProcess- -.class, new ndProcessServerAdapter_RMI());
General- -.setServerForClass(InRoutingConfig.class, new InRoutingConfigServerAdapter_RMI());
General- -.setServerForClass(Queue.class, new QueueServerAdapter_RMI());
General- -.setServerForClass(ndTargetApplication.class, new ndTargetApplicationServerAdapter_RMI());
General- -.setServerForClass(MessagePrefix.class, new MessagePrefixServerAdapter_RMI());
General- -.setServerForClass(Language.class, new LanguageServerAdapter_RMI());
General- -.setServerForClass(ndMandant.class, new MandantServerAdapter_RMI());
General- -.setServerForClass(Mandant.class, new MandantServerAdapter_RMI());
General- -.setServerForClass(UserGroup.class, new UserGroupServerAdapter_RMI());
General- -.setServerForClass(TextResourceBundle.class, new TextHandlerServerAdapter_RMI());
General- -.setServerForClass(Holiday.class, new HolidayServerAdapter_RMI());
General- -.setServerForClass(ndAcknowledgement.class, new AcknowledgementServerAdapter_RMI());
General- -.setServerForClass(InvalidPassword.class, new InvalidPasswordServerAdapter_RMI());
General- -.setServerForClass(SystemParameter.class, new SystemParameterServerAdapter_RMI());
General- -.setServerForClass(ApplParameter.class, new ApplParameterServerAdapter_RMI());
General- -.setServerForClass(ClientApplParameter.class, new ClientApplParameterServerAdapter_RMI());
General- -.setServerForClass(ClientBackendParameter.class, new ClientBackendParameterServerAdapter_RMI());
General- -.setServerForClass(Branch.class, new BranchServerAdapter_RMI());
General- -.setServerForClass(TextHandler.class, new TextHandlerServerAdapter_RMI());
General- -.setServerForClass(ConcHistory.class, new ConcHistoryServerAdapter_RMI());
General- -.setServerForClass(Country.class, new CountryServerAdapter_RMI());
General- -.setServerForClass(SysRouteDelete.class, new SysRouteDeleteServerAdapter_RMI());
General- -.setServerForClass(Statistics.class, new StatisticsServerAdapter_RMI());
General- -.setServerForClass(Department.class, new DepartmentServerAdapter_RMI());
General- -.setServerForClass(OutsourcingControl.class, new OutsourcingControlServerAdapter_RMI());
General- -.setServerForClass(Pricing.class, new PricingServerAdapter_RMI());
General- -.setServerForClass(AccountLength.class, new AccountLengthServerAdapter_RMI());
General- -.setServerForClass(ReorganisationDB.class, new ReorganisationDBServerAdapter_RMI());
General- -.setServerForClass(IntdualcAccount.class, new IntdualcAccountServerAdapter_RMI());
General- -.setServerForClass(IntdualcSettlement.class, new IntdualcSettlementServerAdapter_RMI());
General- -.setServerForClass(ndPricingRemittance.class, new ndPricingRemittanceServerAdapter_RMI());
General- -.setServerForClass(DiSettlement.class, new DiSettlementServerAdapter_RMI());
General- -.setServerForClass(OrgaDb.class, new OrgaDbServerAdapter_RMI());
// which servers are to start?
boolean fStartServerGrp1 = true;
boolean fStartServerGrp2 = true;
boolean fStartServerGrp3 = true;
boolean fStartServerGrp4 = true;
boolean fStartServerGrp5 = true;
// check whether args are set
if (args.length > 0)
{
String strArg = args[0];
if (strArg.equals("1"))
{
fStartServerGrp1 = true;
fStartServerGrp2 = false;
fStartServerGrp3 = false;
fStartServerGrp4 = false;
fStartServerGrp5 = false;
}
if (strArg.equals("2"))
{
fStartServerGrp1 = false;
fStartServerGrp2 = true;
fStartServerGrp3 = false;
fStartServerGrp4 = false;
fStartServerGrp5 = false;
}
if (strArg.equals("3"))
{
fStartServerGrp1 = false;
fStartServerGrp2 = false;
fStartServerGrp3 = true;
fStartServerGrp4 = false;
fStartServerGrp5 = false;
}
if (strArg.equals("4"))
{
fStartServerGrp1 = false;
fStartServerGrp2 = false;
fStartServerGrp3 = false;
fStartServerGrp4 = true;
fStartServerGrp5 = false;
}
if (strArg.equals("5"))
{
fStartServerGrp1 = false;
fStartServerGrp2 = false;
fStartServerGrp3 = false;
fStartServerGrp4 = false;
fStartServerGrp5 = true;
}
}
// Supply Server with client personality of data manager in case
// they have to use it
DataManager dm = new DataManager();
GeneralServer.setDataManager(dm);
GeneralData- -.setDataManager(dm);
// start the servers
//The AuthenticationSever has to be started first because of security (trust-id)
// This is the first server to bind to the registry. But unfortunately
// in some cases when this process created the registry the bind gets a timeout.
// So we try to do this first bind several times before we give up...
boolean fStarted = false;
int iCount = 0;
while (!fStarted)
{
try
{
iCount++;
new AuthenticationServer(true);
fStarted = true;
}
catch (Throwable e)
{
Trace.traceException(e);
// no try anymore
if (iCount >= 10)
throw e;
}
}
//first the DataManager to can check the programm version
new DataManagerServer();
//Cache the current productinstance in the datamanager!
ndProductInstanceData productInstance =
getProductInstance (dm, strProduct, Integer.parseInt(strInstanceNumber));
//check the current version
if (productInstance.getVersion() != null)
{
if (!productInstance.getVersion().equals(c_actualVersion))
{
Trace.traceError("Invalid version!");
Trace.traceError("Actual version: " + c_actualVersion);
Trace.traceError("Needed version: " + productInstance.getVersion());
Trace.traceError("The rmi-process was stopped");
System.exit(-1);
}
}
else
{
Trace.traceError("No version check (no version set in DB)");
}
// do it in groups because of problems with AIX
if (fStartServerGrp1)
{
new ndDateServer();
new MessageServer();
new ndMessageServer();
new LogServer(true);
new HistoryServer(true);
new EventLogServer(true);
new dccEventLogServer(true);
new UserServer(true);
new BackendAccessServer(true);
BackendAccessServer.setMessageClassName("de.entory.dcc.messagedomain.Message");
}
if (fStartServerGrp2)
{
new CustomerServer();
new DepartmentServer(true);
new DccAccountServer ();
new DiAccountServer();
new DiSettlementServer();
new SettlementServer();
new DreCatiSettlementServer();
new DreCatiCurrencyManagerServer();
new DreCatiAccountServer();
new IntdualcAccountServer();
new IntdualcSettlementServer();
new DreCatiTrancheControlServer();
new CurrencyServer ();
new TextHandlerServer();
new ReconciliationServer(true);
new MessageProcessingServer(true);
new MsgAccessServer(true);
new OrgaDbServer();
}
if (fStartServerGrp3)
{
new ProgramServer(true);
new ndProcessServer();
new InRoutingConfigServer(true);
new QueueServer(true);
new ndTargetApplicationServer(true);
new MessagePrefixServer(true);
new BranchServer();
new ReorganisationDBServer();
}
if (fStartServerGrp4)
{
new LanguageServer();
new MandantServer();
new UserGroupServer();
new HolidayServer();
new AcknowledgementServer();
new InvalidPasswordServer();
new SystemParameterServer(true);
new AccountLengthServer();
}
if (fStartServerGrp5)
{
new ApplParameterServer(true);
new ClientApplParameterServer(true);
new ClientBackendParameterServer(true);
new ConcHistoryServer ();
new CountryServer (true);
new SysRouteDeleteServer ();
new StatisticsServer ();
new OutsourcingControlServer ();
new ndPricingRemittanceServer();
new PricingServer();
}
// make the default mandant available to the DBAccess-class
ndMandantData data = dm.getDefaultMandant();
if (data != null)
DBAccess.setDefaultMandantId(data.getId());
else
DBAccess.setDefaultMandantId(null);
// now we have to inform the server that its now acting in a multi thread
// environment
ndPersistenceServer.setMultiThreadSupport(true);
//last, we must save our pid in the table process, to give the master
//the chance, to start us in case of confusion!
if ((c_argProperties.get("p") != null) && (c_argProperties.get("n") != null))
{
String strPnr = (String)c_argProperties.get("p");
String strInr = (String)c_argProperties.get("n");
writePidToProcess (strPnr, Integer.parseInt(strInr));
}
else
Trace.traceError("No actual pid was set (the rmi-server must be started with arguments!)");
// now prepare the meta data if requested
//Writing metadata should occur after writing the pid, because this
// action runs a couple of time, and the master want not wait so long!
if ((System.getProperty("db.md_cacheonstartup") == null) ||
!(System.getProperty("db.md_cacheonstartup").equals("0")))
prepareMetaData ();
}
catch (RemoteException e)
{
Throwable ex = e.detail;
ex.printStackTrace();
Trace.traceError("Fatal error: the rmi-serverprocess was stopped!");
System.exit(-1);
}
catch (Throwable e)
{
e.printStackTrace();
Trace.traceError("Fatal error: the rmi-serverprocess was stopped!");
System.exit(-1);
}
}
private static ndProductInstanceData getProductInstance (DataManager dm, String product, int instance) throws Exception
{
ndProductInstanceData searchData = new ndProductInstanceData();
searchData.setInstanceNumber(instance);
searchData.setProduct(product);
return (dm.getProductInstance (searchData));
}
private static void setCryptFilePath(String strPath)
{
SecuritySupport.setPathNdCrypt(strPath);
}
private static void writePidToProcess (String programName, int instNr)
{
int pid = getPid();
if (pid == -1)
{
Trace.traceError("Error reading PID from file " + getPidFileName());
Trace.traceError("The Table process was not updated!");
}
else
{
try
{
//Get the programNr for the programname from table program
ProgramSearchData prgramSearch = new ProgramSearchData ();
prgramSearch.setName(programName);
prgramSearch.setOnlyValidProgram(true);
Vector<?> v = Program.search(prgramSearch);
Assertion.verify(v.size() == 1);
int programNr = Integer.parseInt(((ProgramData)v.firstElement()).getId());
//Update process
ndProcessData data = new ndProcessData();
data.setActualPid(new Integer (pid));
data.setProgram(new Integer (programNr));
data.setInstanceNr(new Integer (instNr));
ndProcess- -.setActualPid(data);
Trace.traceInfo("The actual pid was set");
}
catch (GeneralException e)
{
Trace.traceError("The actual pid couldn't be updated!");
}
}
}
private static int getPid ()
{
int pid = -1;
А это возможно только если позволить апплету, вылезать из своей песочницы, например, менять переменные среды. Или писать в файл.
Писать в файл?
А что, это идея. Надо подумать. В файл или в БД, без разницы.
При залогинивании и перелогинивании он, естественно, тоже не меняется.
-----
Это как раз не естественно для веба...
Согласен, для веба не естественно, но для описанной мной выше ситуации - естественно.
Товарищи, это П№;%:ЕЦ! Поймайте аффтора этого .... продукта вторичной переработки и дефабержируйте его. Не дай бог он размножаться будет.
Почему вы говорите о сервлете, если ваш StartServer это простое приложение, запускающее RMI-шный сервер?
Решения, конечно, нет, я лишь хотел удостовериться, что дело именно в двух Ява-машинах.
А пока я и причины не знаю, трудно что-то лечить.
Хозяин - барин. Посмотрите в Task Manager-е, например, сколько явовских процессов у вас бегает. Но ели у вас не прав локального администратора вы все процессы можете и не увидеть.
Причины я вам раза три назвал. Ваша логика работать может только по случайному стечению обстоятельств (и, похоже, только в микроштофовском иксплодере). По-хорошему и третий апплет не должен был ничего увидеть и так же запуститься как и предыдущие два.
В принципе можно вообще работать, не залогиниваясь (при отключенной секьюрити), что мы часто и делаем. Вы же не будете говорить, что в этом случае нет никакой сессии?
Я лучше промолчу. Потому как я не понимаю что вы называете сессией и где ее у вас нет (или есть). Пока что я видел только что вы явно используете RMI-шный сервер.
01.09.2015 12:27:23 DCC_4 (25) I: request for access key: 540C407B5B9122D19AFC1588C2A49579
01.09.2015 12:27:23 DCC_4 (PP_AuthenticationServer) I: getMandantFor: 540C407B5B9122D19AFC1588C2A49579
А откуда берется это значение? (540C407B5B9122D19AFC1588C2A49579) Кто его генерирует, или оно прошито в клиента?
При залогинивании и перелогинивании он, естественно, тоже не меняется.
Сурово. При запуске нового клиента он тоже не меняется?
При запуске веб-сервера или при вызове doGet() или doPost()?
Второе.
Все чудесатее и чудесатее. Вы при каждом входящем на веб-сервер GET запросе, попадающем на ваш сервлет (у вас точно есть сервлет? Класс extends HttpServlet?) что запускаете? StartServer.main(new String[0])?
Покажите код doGet()
Как ваш апплет общается с сервером? RMI? (у вас ведь точно апплет, да?)
А что, это идея. Надо подумать. В файл или в БД, без разницы.
Не-не-не Дэвид Блэйн! Не надо думать эту идею. Это плохая, негодная идея. Вы не представляете сколько геморроя вы себе наживете при попытке разрешить апплету доступ к диску. Разве что вы можете на каждой машине, на которой он будет запускаться, явовские настройки безопасности поменять...
Даю намек - а в чем разница между сервером БД и вашим собственным сервером (сервлет, RMI-сервер, CORBA или что вы используете-то)?
Соответственно, это помешает повторному логину.
Можно ввести дополнительное поле в таблице пользователей БД, которое отвечает за то, залогинен пользователь или нет.
Так просто у ТС не получится. У него второй пользователь (с другим логином/паролем) портит то, что делал первый, потому как...
Второе окно открывать запрещено, но по какой-то причине оно все же открывается, пользователи заходят под другим логином, чтобы валидировать данные
Проблема в том, что и в первом, и во втором окне - одна и та же сессия, эта сессия привязана только к IP компутера.
В результате второй юзер портит то, что делает первый, и наоборот, т.к. ряд переменных действительны для всей сессии.
У базы данных - свой сервер, понятно. Но все же это предотвратило бы хотя бы бОльшую часть попыток создания второго окна. Это уже что-то, нет?
Нет, немного иначе, поскольку речь идет о разных логинах (там такая схема, что валидировать изменения, произведенные в БД одним юзером, может только другой юзер, поэтому вот так это предписание и обходится левым образом, иначе много геморроя).
Т.е. есть реальные люди и есть аккаунты - это разные вещи. На одной Юникс-машине могут одновременно работать несколько человек. По той схеме, что Вы предлагаете, сможет работать только один.
Так что привязка должна быть не к к аккаунту, а все-таки к ID сессии, которое принадлежит одному человеку, именно это значение должно проверяться, если такое ID уже зарегистрировано, то второе окно не открываться.. Нет, впрочем, это тоже не годится. А что, если юзер закрыл окно и ушел? Завтра придет - сессия та же, окно не открывается?
Я думаю, решение надо искать в том, что насильственно перезапускать сессию, но как? Один жесткий тайм аут на Томкате ведь не поможет.
Товарищи, это П№;%:ЕЦ! Поймайте аффтора этого .... продукта вторичной переработки и дефабержируйте его. Не дай бог он размножаться будет.
Его уже и след простыл. Я понятия не имею, кто это был. Наверно, в Яве он рубит примерно так же, как и я, который на ней никогда раньше ничего не делал. Хотя, скорее, лучше :)
>> Хозяин - барин. Посмотрите в Task Manager-е, например, сколько явовских процессов у вас бегает. Но ели у вас не прав локального администратора вы все процессы можете и не увидеть.
У меня там явовские процессы, не только с этим связанные. Сам Эклипс тоже запускает явовский процесс.
>> Причины я вам раза три назвал. Ваша логика работать может только по случайному стечению обстоятельств (и, похоже, только в микроштофовском иксплодере). По-хорошему и третий апплет не должен был ничего увидеть и так же запуститься как и предыдущие два.
Да, но на третьем окне всегда строго срабатывает. Всегда!
И Ява-консоли всегда две. Не говорит ли это о том, что и ява-машины в браузере запускаются ровно две?
>> А откуда берется это значение? (540C407B5B9122D19AFC1588C2A49579) Кто его генерирует, или оно прошито в клиента?
А фиг его знает, сейчас, как Вы понимаете, не могу посмотреть. И код до понедельника не могу прислать.
Прошито - нет, не прошито, оно меняется.
>> Сурово. При запуске нового клиента он тоже не меняется?
В том-то и дело, что нет! Если машина (винда) и айпак те же, то при запуске нового клиента не меняется. А логин уже потом происходит. И после него, естественно, тоже не меняется.
>> Как ваш апплет общается с сервером? RMI? (у вас ведь точно апплет, да?)
Да, RMI, да, точно апплетка.
Да, но на третьем окне всегда строго срабатывает. Всегда!
Всегда это значит на одной и той же машине на одном и том же браузере одной и той же версии запускающем JRE одной и той же версии. То что эта проверка срабатывает сейчас, не факт что она сработает с другим браузером и с другой версией явы.
url поправлен
К сожалению, параноидальные настройки форума портят всё, где слово скрипт и апплет в английской транскрипции написаны.
http://docs.oracle.com/javase/6/docs/technotes/guides/jweb/applet/applet_execution.html
Так должно сработать
Сейчас апплеты загруженные с того же самого codebase и с тем же самым архивом могут быть запущены в одном JRE. Никто не гарантирует что они будут запущены в одном.
Вроде как есть трюк - из неподписанного апплета писать и читать куки через яваскрипт используя JSObject. Опять же - трюк, даже если он у вас сработает сейчас не факт что он сработает после апдейта явы или браузера.
И Ява-консоли всегда две. Не говорит ли это о том, что и ява-машины в браузере запускаются ровно две?
Говорит. Говорит ли это что-то о том что никогда не будет запущена третья или четвертая? Нет.
Да, RMI, да, точно апплетка.
Подведем итоги. Процесс у вас такой.
1. Запускается веб-сервер.
2. На вебсервере поднимается ваш сервлет.
3. Ваш сервлет запускат с помощью класса StartServer RMI сервер на той же машине, на которой поднят веб-сервер.
4. Юзер Ю открывает в браузере страничку на которой находится ваш апплет.
5. В это момент у вас (под контролем непонятно кого) запускается (вернее этот кто-то по волшебству узнает что за клиент и откуда-то берет или делает новую сессию) ваша "сессия" (точно не томкатовская HttpSession?). Апплет к RMI серверу пока что не обращался.
6. Апплет А1 предлагает юзеру залогинится, юзер вводит логин/пароль Х.
7. А1 по RMI аутентифицирует логин юзера Ю как Х.
8. Ю открывает второе окно браузера, в котором открывает ту же страничку.
9. Каким-то колдунством кто-то выясняет что это юзер Ю с той же машины, и диалог с 2-м апплетом (А2) пойдет в той же самой сессии что и с А1.
10. А2 предлагает юзеру залогинится, юзер вводит логин/пароль У.
11. А2 по RMI аутентифицирует логин юзера Ю как У.
12. А1 и А2 параллельно работают с данными через RMI, оба логина и Х и У имеют права не только на чтение но и на модификацию данных, так как доступ к данным авторизируется сессией, а она у них одна.
13. А1 и А2 помирают, потому как Ю не логаутится а просто выключает браузер. Сессия остается (все там же, черт знает где).
Поправьте меня где я ошибся. Или если все неправильно - напишите как оно на самом деле происходит.
-----
Вот при успешном логине и убивай текущую сессию и создавай новую. Будут, правда,
недовольные потерей данных в сессии юзвери, но это меньшая и решаемая проблема
по сравнению с разбором полетов тех же юзверей в одной сессии.
Как именно прибивать - надо смотреть как оно организовано - у тебя там что нестандартное.
На одной Юникс-машине могут одновременно работать несколько человек.
------
Только не говори, что все они будут сидеть в одной сессии - в этом случае решения
просто не будет.

Вопросик из области Web-Programmierung
-----
Мои советы были по ситуации именно в заявленном тобой контексте.
У тебя же от этого имеется пожалуй только статичная <HTML>-страничка.
Все остальное - <RMI> - с которым Я может быть и справлюсь, но давать
какие-либо советы - воздержусь - уже лет 15-ть его не видел.
П.С. Зарезав все кроме 80-го порта ты бы получил просто неработающий
<RMI> - у него дефаултный порт 1099. Это простейший тест на Веб-ность
системы и дальше бы искали что там не так.
>> точно не томкатовская HttpSession?
Скорее всего она.
>> 9. Каким-то колдунством кто-то выясняет что это юзер Ю с той же машины, и диалог с 2-м апплетом (А2) пойдет в той же самой сессии что и с А1.
Никакого колдовства нет, по-видимому, сессия привязана к IP.
>> 12. А1 и А2 параллельно работают с данными через RMI, оба логина и Х и У имеют права не только на чтение но и на модификацию данных, так как доступ к данным авторизируется сессией, а она у них одна.
Почти так. Я опустил для простоты, что там они еще выбирают некоего "манданта" (всего этих мандантов три, один называется "дефолт", другой основной, а третий - *. В базе данных прописаны только первые два. Изменять данные имеет право только основной мандант, остальные два имеют только права на чтение, вот тут и возникает проблема: если в одном окне выбран дефолт или *, то измененные данные записываются на счет дефолта и в итоге теряются). Но для того, чтобы решить проблему, все это несущественно.
>>13. А1 и А2 помирают, потому как Ю не логаутится а просто выключает браузер. Сессия остается (все там же, черт знает где).
На веб-сервере?
>> Вроде как есть трюк - из неподписанного апплета писать и читать куки через яваскрипт используя JS- -.
А что такое "неподписанный" апплет?
Разве на самой Яве читать куки и писать в них нельзя? (если вопрос глупый, не убивайте, никогда с этим дела не имел)
Ну, и главное: если окно закрывается, куки об этом узнают?
недовольные потерей данных в сессии юзвери, но это меньшая и решаемая проблема
по сравнению с разбором полетов тех же юзверей в одной сессии.
Ну, поскольку юзеры - это наше фахабтайлюнг, то я им ничего предписывать не могу.
И потом, как это убивать сессию после логина? Заставлять их логиниться два раза подряд?
Так они явно будут против.
>> На одной Юникс-машине могут одновременно работать несколько человек.
------
>> Только не говори, что все они будут сидеть в одной сессии - в этом случае решения
просто не будет
Нет, нет, каждый из них сидит в своей сессии.
-------
Именно за этим - логинится снова. Но не два раза подряд, а тогда, когда юзер посчитает
нужным перейти в другое окно на той же системе.
фахабтайлюнг
------
Я не немец - мне твои ругательства не понятны.
Нет, нет, каждый из них сидит в своей сессии.
------
Ну тогда у меня возникает сильное непонимание - сессии привязны к ИП и только ИП, ИП, как правило,
на машине один, юзверей - несколько. Где-то что-то есть не правильно...
------
Когда закрувается окно, то в бровсере, обычно доступно для <JS> событие закрытия окна.
Соответственно, можно прописать в куках, что событие закрытия имело место.
Аналогично и по открытию окна - есть событие открытия окна и возможность что-то сделать.
Пользоваться этим, однако, не стоит - не при всяком закрытии окна будет иметь место это
событие.
Но это - <Java S cript>. Как это делается из апплета - не знаю.
Скорее всего она.
Тогда она скорее всего не связана с IP адресом. Насколько я помню томкат а.) такого не умеет б.) считать что все запросы приходящие с одного IP принадлежат одной сессии - большая дыра в безопасности.
Посмотрите, у вас куки JSESSIONID для вашего сервера (его домена) в IE появляется? Какое у нее значение? Тоже самое что выдает ваш лог в "DCC_4 (25) I: request for access key: 540C407B5B9122D19AFC1588C2A49579" Скорее всего у вас идентифиация по куки используется.
Сессия остается (все там же, черт знает где).
На веб-сервере?
Если она остается на веб-сервере то она через полчаса помрет. Стандартная настройка томката - время жизни Http сессии 30 минут.
А что такое "неподписанный" апплет?
Что такое SSL сертификат знаете? Апплеты можно подписывать (sign). Подписанному (signed) апплету браузер может дать право выйти из "песочницы" - читать и писать файлы, открывать соединения с другими хостами, читать системные переменные, изменять куки и те пе.
Неподписанному апплету браузер доверять не имеет права. Почитайте, например, docs.oracle.com/javase/tutorial/deployment/applet/security.html
Ну, и главное: если окно закрывается, куки об этом узнают?
На этот вопрос я могу ответить четко и однозначно: "когда как" :)
Комбинировать надо. Куки без expiration удаляются браузером когда он закрывается. Но не отдельный таб. Чтобы при закрытии отдельного таба удалить определенные куки - яваскрптом ловим (как его правильно, этот ивент... ) unload вроде бы у окна и сами их трем.
У меня еще один вопрос возник - а как ваш апплет общается с RMI сервером? Вообще-то на другой порт (1099) соединение неподписанному (не привелигериванному) апплету открывать нельзя.
И давайте сформулируем что же вам надо. "запретить открытие второго окна" = не давать больше чем одному логину (X и Y в моем примере) работать в одной и той же сессии
Т.е. если в сессии S1 (с идентификатором вроде 540C407B5B9122D19AFC1588C2A49579) уже залогинен пользователь как X, то не давать еще одному пользователю логинится (как X или как Y - не важно) в этой же сессии?
А в другой сессии S2 (с другим идентификатором, с другого компьютера, например) можно?
Или что-то другое?
И потом, как это убивать сессию после логина? Заставлять их логиниться два раза подряд?
-------
Именно за этим - логинится снова. Но не два раза подряд, а тогда, когда юзер посчитает
нужным перейти в другое окно на той же системе.
Тогда я не понял, что Вы имеете в виду.
Юзер залогинился, после этого убивается сессия. А как он работать будет, без сессии?
Я не немец - мне твои ругательства не понятны.
Непрграммистское начальство.
Нет, нет, каждый из них сидит в своей сессии.
------
Ну тогда у меня возникает сильное непонимание - сессии привязны к ИП и только ИП, ИП, как правило,
на машине один, юзверей - несколько. Где-то что-то есть не правильно...
Они сидят на одной Юникс-машине, но компы-то у каждого свои и айпаки тоже свои.
Искал здесь: C:\WINDOWS\Profiles\cb3wech\Local Settings\Temporary Internet Files, но и в других местах тоже.
Тогда она скорее всего не связана с IP адресом. Насколько я помню томкат а.) такого не умеет б.) считать что все запросы приходящие с одного IP принадлежат одной сессии - большая дыра в безопасности.
Но эта дыра уже есть де-факто.
Посмотрите, у вас куки JSESSIONID для вашего сервера (его домена) в IE появляется?
Нет.
Если она остается на веб-сервере то она через полчаса помрет. Стандартная настройка томката - время жизни Http сессии 30 минут.
Но только при неактивности, как я понимаю.
У меня еще один вопрос возник - а как ваш апплет общается с RMI сервером? Вообще-то на другой порт (1099) соединение неподписанному (не привелигериванному) апплету открывать нельзя.
Апплет подписанный, я просто не понял вчера Вашего вопроса.
И давайте сформулируем что же вам надо. "запретить открытие второго окна" = не давать больше чем одному логину (X и Y в моем примере) работать в одной и той же сессии
Т.е. если в сессии S1 (с идентификатором вроде 540C407B5B9122D19AFC1588C2A49579) уже залогинен пользователь как X, то не давать еще одному пользователю логинится (как X или как Y - не важно) в этой же сессии?
А в другой сессии S2 (с другим идентификатором, с другого компьютера, например) можно?
Да, именно так, совершенно точно
------
Когда второй юзер логинится - у тебя уже есть сессия первого (с того же хоста) залогиненного юзера - вот ее и надо прибить.
Они сидят на одной Юникс-машине, но компы-то у каждого свои и айпаки тоже свои.
------
Пожалей мою голову - у меня ведь тоже работа и ее делать надо..
Ну хоть немножко привел бы в порядок мысли.
Как Я читаю:
- есть Юникс
- у Юникса есть ИП
- на Юниксе работают несколько пользователей... ну ладно - несколько <BASH>ей запущено...
Дальше:
- у каждого свой комп - это внутри Юникса? Используется какая-то ВМ?
- и ИП свои - получается что-то непотребное - взяли никсовый ИП и порезали на части для юзверей...
Бред? Угу...
Когда ты обьяснишь, что на Юниксе крутится <RMI>-сервер, то возникнет несколько вопросов
- все клиенты обслуживаются одним работающим сервисом или для каждого поднимается свой
сервер. Бо, если сервер один, то там как-то диспетчируются запросы и в том месте надо смотреть
как быть с пользователем. Ну а если под каждого свой сервер - то надо искать наличие дыры и
возможности просмотреть всех залогиненных юзверей...
Соединение по RMI делается только в Эклипсе, для тестирования.
На браузере для этого используется сервлет.
Сейчас я и Эклипс переключил на сервлет, пытаюсь соединиься со скачанным на винду Томкатом.
Тайм аут установлен на 7200 минут, это ровно 10 дней, сессия - на Томкате, с http, и абсолютно точно привязана к IP, это я проверил.
Когда второй юзер логинится - у тебя уже есть сессия первого (с того же хоста) залогиненного юзера - вот ее и надо прибить.
Да, до этого я уже допер
Только старая сессия не должна убиваться, надо просто запускать новую для нового юзера и не портить настроение соседу (ну, т.е. самому себе, если не понятно).
Вот как именно запускать ее, я еще не разобрался, не подскажешь?
Пожалей мою голову - у меня ведь тоже работа и ее делать надо..
Ну хоть немножко привел бы в порядок мысли.
Как Я читаю:
- есть Юникс
- у Юникса есть ИП
- на Юниксе работают несколько пользователей... ну ладно - несколько <BASH>ей запущено...
Дальше:
- у каждого свой комп - это внутри Юникса? Используется какая-то ВМ?
- и ИП свои - получается что-то непотребное - взяли никсовый ИП и порезали на части для юзверей...
Бред? Угу...
Ты лучше бы сам подумал своей головой. Какой еще IP у Юникса, тыачем, ау?
Каждый юзер сидит за своим компом с Виндой, у этого компа есть IP.
Все эти компы коннектятся к одной Юникс-машине.
Когда ты обьяснишь, что на Юниксе крутится <RMI>-сервер, то возникнет несколько вопросов
- все клиенты обслуживаются одним работающим сервисом или для каждого поднимается свой
сервер.
См. выше. RMI у каждого свой и только для тестирования на Эклипсе. В боевых условиях вместо RMI используется сервлет.
-----
Угу... Будет вместо поиска решения проблемы - Один хост = Одна сессия, поиск решения - Много Сессий = Много Юзеров... и все - без идентификации, чисто по ИП, без СИДов. Удачки, как говорится...
не подскажешь?
------
Увы - ТомКат, вроде, появился после того, как Я перестал работать с Жабой...
Тогда была ВебСфера от ИБМ и что-то еще. Что - не помню - мне не до этих
моментов было - код надо было делать.
Ты лучше бы сам подумал своей головой.
------
Я и думаю - над своими задачами. Еще чуток и на твои отвлекаюсь. Могу - не отвлекаться.
В боевых условиях вместо RMI используется сервлет.
------
Ты запутал пожалуй уже всех.
У тебя при обрезке на файрволе всего, кроме 80 порта, приложение работает?
Если - НЕТ - это не заявленный веб. Что именно и когда у тебя используется - надо сидеть
и разбираться. Насколько при этом то, что ты описываешь соответствует той (а она использовалась
15 лет назад и подзабыта основательно) терминологии которой Я оперирую - тоже очень большой
вопрос. Так что есть смысл коротко описать что-есть-что и показать на минимальных примерах.
Какой еще IP у Юникса, тыачем, ау?
------
Он в Сети? К нему коннектятся по <tcp/ip> протоколу? - там без ИП не работает...
Если еще проще - веб-сервер/апп-сервер без ИП не запускается - ему требуется ИП для открытия
порта для прослушки... Ау?
Угу... Будет вместо поиска решения проблемы - Один хост = Одна сессия, поиск решения - Много Сессий = Много Юзеров... и все - без идентификации, чисто по ИП, без СИДов. Удачки, как говорится...
Ну, это ты не мне объясняй, а нашим юзерам.
Им надо в одном окне изменения делать, а в другом валидировать.
Сессий будет всего две, ничего страшного не вижу.
Я и думаю - над своими задачами. Еще чуток и на твои отвлекаюсь. Могу - не отвлекаться.
Сорри. Но ты тоже не обзывайся.
Ты запутал пожалуй уже всех.
У тебя при обрезке на файрволе всего, кроме 80 порта, приложение работает?
Понятия не имею.
Насколько при этом то, что ты описываешь соответствует той (а она использовалась
15 лет назад и подзабыта основательно) терминологии которой Я оперирую - тоже очень большой
вопрос. Так что есть смысл коротко описать что-есть-что и показать на минимальных примерах.
Ну, какие еще примеры-то нужны?
Сидят, допустим, три юзера, у каждого свой комп с виндой, ходят через браузер на одну Юникс-машину (на самом деле не на одну, а на кучу, но для простоты будем считать, что на одну).
Какой еще IP у Юникса, тыачем, ау?
------
Он в Сети? К нему коннектятся по <tcp/ip> протоколу? - там без ИП не работает...
В логе стоит мой личный IP, который я в ipconfig вижу.
Если еще проще - веб-сервер/апп-сервер без ИП не запускается - ему требуется ИП для открытия
порта для прослушки... Ау?
В науке о портах и гаванях я не силен, запускать веб-сервер - не моя забота, я его одной командой (кнопкой) запускаю, а на продукционной и прочих боевых машинах он и так всегда запущен. Мы говорим только про запуск апплета.
------
Твои юзера есть ТВОИ юзера. У меня есть МОИ юзера которым приходится обьяснять "элементарные" вещи. Обьяснять по многу раз ибо с выполняемой ими работой мои обьяснения связаны только косвенно. И вариантов у меня два - бегать за каждым юзером или сделать так, чтобы они не имели возможность что-то сломать... ну или при сломе можно было восстановить на раз-два. По этому если Я не могу различить юзеров в сессии - то будет одна сессия на комп.
Им надо в одном окне изменения делать, а в другом валидировать.
Сессий будет всего две, ничего страшного не вижу.
-----
Сессий бывает - Ноль, Одна и МНОГО. Страшного ничего не будет - ты будешь в той же позиции, что и в начале - никаких других сложностей не будет.
Сорри. Но ты тоже не обзывайся.
-----
Мне - можно - Я старый и раздражительный... и этикет у меня времен ФИДО. Он не мешает сказать оппоненту, что тот не прав.
ходят через браузер на одну Юникс-машину
Соединение с Томкатом через сервлет по IP виндокомпутера.
------
Хммм... Эквивалентно - Едя по автобану на Юг мы пешком по буеракам идем север.
В каком же направлении движение то?
В науке о портах и гаванях я не силен
------
Да, это видно. Потому тебя и тыкаю носом в несоответствия - что бы задумался и осознал. Там, если не углублятся до уровня сокетов и ниже, не сложно, но понимать что и как, хотя бы схематично - надо.
запускать веб-сервер - не моя забота, я его одной командой (кнопкой) запускаю
------
Угу... где-то в самом начале тебе рекомендовалось разобраться что и на какой машине выполняется. Когда ты запускаешь веб-сервер локально у тебя - учитывая твой сишный опыт и непонимание "портов и гаваней" - не получается точно осознать где какой кусок кода выполняется. Ну а код состоит из двух частей: одна работает на сервере, а вторая - на клиенте. Плюс - коммуникация через "порты и гавани".
Мы говорим только про запуск апплета.
------
Про отслеживание повторного запуска апплета тебе уже все разжевали - решения на клиенте нет и быть не может. А каким образом ты ходишь на сервер мне пока не понятно. Предположения - да, есть, но вариантов много...
Надо не давать больше чем одному логину работать в одной и той же сессии. В разных сессиях можно сколько угодно разных логинов, но одна сессия - один логин.
Надо надежно отслеживать что пользователь прекратил работу, даже если он не делал логаут, а просто закрыл окно браузера.
сессия - на Томкате, с http, и абсолютно точно привязана к IP, это я проверил.
А как вы проверили? Лично я не знаю такой реализации Manager-а, который заставит томкат использовать одну и ту же сесстю для одного IP. Как у вас сконфигурирован Manager в Context-е?
Покажите код сервлета, который вызывается когда пользователь логинится. До логина апплет обращается к сервлету?
Допустим все именно так, у нас HttpSession, привязанная к IP и живущая 10 дней (кто ж до такого догадался-то...)
Кто виноват - понятно, аффтар жжот. Что делать? Ничего хорошего.
Апплет у вас как-то идентифицируется, несмотря на то что общение с сервером идет в одной сессии, или нет?
Т.е. если на одной машине открыты два окна, в обоих юзер залогинится используя один и тот же логин X, на сервлет пришел какой-то запрос, вы можете понять от какого из двух апплетов он пришел?
Если мы может разделять пользователей (для каждого запроса, пришедего на сервлет, мы можем прочитать из запроса или создать идентификатор клиента uniqueClientId), то сработает такое:
1. При логине смотрим в HttpSession (метод getAttribute(String))- есть ли у нас аттрибут CURRENT_LOGIN
1.1 нет аттрибута. Значит в этой сессии никто не залогинен. Разрешаем логин
session.setAttribute("CURRENT_LOGIN", uniqueClientId);
session.setAttribute("LAST_ACTION_TIME", System.currentTimeMillis());
1.2 есть аттрибут. Проверяем не вылетел ли этот пользоватль по таймауту. Читаем из сессии LAST_ACTION_TIME
final long currentTime = System.currentTimeMillis();
final boolean loginTimedOut;
if(session.getAttribute("LAST_ACTION_TIME")==null){
loginTimedOut = false;
} else {
final long lastActionTime = (Long)session.getAttribute("LAST_ACTION_TIME");
loginTimedOut = currentTime > lastActionTime + inactivityTimeout; // inactivityTimeout, например, равен 15*60*1000 (15 минут)
}
1.2.1 loginTimedOut == true. Пользователь с этим логином слишком долго ничего не делал. Меняем его логин.
session.setAttribute("CURRENT_LOGIN", uniqueClientId);
session.setAttribute("LAST_ACTION_TIME", System.currentTimeMillis());
1.2.2 loginTimedOut = false Логин активен - новый логин запрещен
2. При каждом запросе от апплета смотрим от кого он пришел, если ID логина (uniqueClientId) совпадает с тем, что в сессии в аттрибуте CURRENT_LOGIN лежит, актуализируем LAST_ACTION_TIME и выполняем запрос.
Если не совпадает (запрос может придти от старого апплета, с логином, который был замещен новым из-за неактивности) собщаем об ошибке и закрываем апплет.
А как вы проверили?
В сессии проверяется IP.
public class AuthenticationData
...
public void reset ()
{
...
if (Current- -Context.getC_local_ip() != null )
localIP = Current- -Context.getC_local_ip();
else
localIP = "";
}
public class LogonPanel
locUser = User.logon(m_efUserID.getText(), strEncrypt, strNewEncrypt, curMandant.getId(),
Current- -Context.getC_local_ip());
Ну, и т.д.
лично я не знаю такой реализации Manager-а, который заставит томкат использовать одну и ту же сесстю для одного IP. Как у вас сконфигурирован Manager в Context-е?
public class Current- -Context
private static GeneralSaveInBufferManager c_saveInBuffer = null;
private Current- -Context()
{
c_saveInBuffer = GeneralSaveInBufferManager.getInstance();
}
public static void putSaveInBuffer- - (General- - obj) throws GeneralException
{
if (c_saveInBuffer == null)
{
c_saveInBuffer = GeneralSaveInBufferManager.getInstance();
}
c_saveInBuffer.addGeneralData- -(obj);
}
public static GeneralSaveInBufferManager getSaveInBufferManager()
{
if (c_saveInBuffer == null)
{
c_saveInBuffer = GeneralSaveInBufferManager.getInstance();
}
return (c_saveInBuffer);
}
public static String getC_local_ip() {
return c_local_ip;
}
public static void setC_local_ip(String c_local_ip) {
Current- -Context.c_local_ip = c_local_ip;
}
Покажите код сервлета, который вызывается когда пользователь логинится. До логина апплет обращается к сервлету?
public synchronized InputStream sendRequest(Serializable obj) throws Throwable
{
showInfo("Open connection to servlet: " + m_servlet.toString());
m_connection = m_servlet.openConnection();
// Prepare for both input and output
m_connection.setDoInput(true);
m_connection.setDoOutput(true);
// Turn off caching
m_connection.setUseCaches(false);
// Set the content type to be java-internal/classname
m_connection.setRequestProperty("Content-Type",
"java-internal/" + obj.getClass().getName());
// Write the serialized - - as post data
- -OutputStream out = new - -OutputStream(m_connection.getOutputStream());
out.write- -(obj);
out.flush();
out.close();
return m_connection.getInputStream();
}
public void prepareCommunicationAdapter() throws GeneralException
{
super.prepareCommunicationAdapter();
// set mappings for used client personalities dependent on current communication
if (ndController.isServletCommunication())
{
GeneralServerAdapter_Servlet.setDefaultServletClass(ndServlet.class);
MessageProcessingServerAdapter_Servlet msgProcessingServletAdapter = new MessageProcessingServerAdapter_Servlet();
ndDate.setServerForClass(ndDate.class, new ndDateServerAdapter_Servlet());
DccAccount.setServerForClass(DccAccount.class, new DccAccountServerAdapter_Servlet());
Settlement.setServerForClass(Settlement.class, new SettlementServerAdapter_Servlet());
DreCatiSettlement.setServerForClass(DreCatiSettlement.class, new DreCatiSettlementServerAdapter_Servlet());
DreCatiCurrencyManager.setServerForClass(DreCatiCurrencyManager.class, new DreCatiCurrencyManagerServerAdapter_Servlet());
DreCatiAccount.setServerForClass(DreCatiAccount.class, new DreCatiAccountServerAdapter_Servlet());
DreCatiAccount.setServerForClass(DreCatiTrancheControl.class, new DreCatiTrancheControlServerAdapter_Servlet());
DiAccount.setServerForClass(DiAccount.class, new DiAccountServerAdapter_Servlet());
ndAcknowledgement.setServerForClass(ndAcknowledgement.class, new AcknowledgementServerAdapter_Servlet());
ApplParameter.setServerForClass(ApplParameter.class, new ApplParameterServerAdapter_Servlet());
ClientApplParameter.setServerForClass(ClientApplParameter.class, new ClientApplParameterServerAdapter_Servlet());
ClientBackendParameter.setServerForClass(ClientBackendParameter.class, new ClientBackendParameterServerAdapter_Servlet());
Authentication.setServerForClass(Authentication.class, new AuthenticationServerAdapter_Servlet());
BackendAccess.setServerForClass(BackendAccess.class, new BackendAccessServerAdapter_Servlet());
Branch.setServerForClass(Branch.class, new BranchServerAdapter_Servlet());
Currency.setServerForClass(Currency.class, new CurrencyServerAdapter_Servlet());
CurrentState.setServerForClass(CurrentState.class, msgProcessingServletAdapter);
Customer.setServerForClass(Customer.class, new CustomerServerAdapter_Servlet());
DataManager.setServerForClass(DataManager.class, new DataManagerServerAdapter_Servlet());
EventLog.setServerForClass(EventLog.class, new EventLogServerAdapter_Servlet());
dccEventLog.setServerForClass(dccEventLog.class, new dccEventLogServerAdapter_Servlet());
History.setServerForClass(History.class, new HistoryServerAdapter_Servlet());
Holiday.setServerForClass(Holiday.class, new HolidayServerAdapter_Servlet());
InRoutingConfig.setServerForClass(InRoutingConfig.class, new InRoutingConfigServerAdapter_Servlet());
InvalidPassword.setServerForClass(InvalidPassword.class, new InvalidPasswordServerAdapter_Servlet());
Language.setServerForClass(Language.class, new LanguageServerAdapter_Servlet());
LocalUser.setServerForClass(LocalUser.class, new UserServerAdapter_Servlet());
Log.setServerForClass(Log.class, new LogServerAdapter_Servlet());
Mandant.setServerForClass(Mandant.class, new MandantServerAdapter_Servlet());
ndMandant.setServerForClass(ndMandant.class, new MandantServerAdapter_Servlet());
Message.setServerForClass(Message.class, new MessageServerAdapter_Servlet());
ndMessage.setServerForClass(ndMessage.class, new ndMessageServerAdapter_Servlet());
MessagePrefix.setServerForClass(MessagePrefix.class, new MessagePrefixServerAdapter_Servlet());
MissingState.setServerForClass(MissingState.class, msgProcessingServletAdapter);
MsgAccess.setServerForClass(MsgAccess.class, new MsgAccessServerAdapter_Servlet());
ndProcess- -.setServerForClass(ndProcess- -.class, new ndProcessServerAdapter_Servlet());
ProcessedState.setServerForClass(ProcessedState.class, msgProcessingServletAdapter);
Program.setServerForClass(Program.class, new ProgramServerAdapter_Servlet());
Reconciliation.setServerForClass(Reconciliation.class, new ReconciliationServerAdapter_Servlet());
Queue.setServerForClass(Queue.class, new QueueServerAdapter_Servlet());
SystemParameter.setServerForClass(SystemParameter.class, new SystemParameterServerAdapter_Servlet());
ndTargetApplication.setServerForClass(ndTargetApplication.class, new ndTargetApplicationServerAdapter_Servlet());
TextHandler.setServerForClass(TextHandler.class, new TextHandlerServerAdapter_Servlet());
TextResourceBundle.setServerForClass(TextResourceBundle.class, new TextHandlerServerAdapter_Servlet());
User.setServerForClass(User.class, new UserServerAdapter_Servlet());
UserGroup.setServerForClass(UserGroup.class, new UserGroupServerAdapter_Servlet());
ConcHistory.setServerForClass(ConcHistory.class, new ConcHistoryServerAdapter_Servlet());
Country.setServerForClass(Country.class, new CountryServerAdapter_Servlet());
SysRouteDelete.setServerForClass(SysRouteDelete.class, new SysRouteDeleteServerAdapter_Servlet());
Statistics.setServerForClass(Statistics.class, new StatisticsServerAdapter_Servlet());
Department.setServerForClass(Department.class, new DepartmentServerAdapter_Servlet());
OutsourcingControl.setServerForClass(OutsourcingControl.class, new OutsourcingControlServerAdapter_Servlet());
ndPricingRemittance.setServerForClass(ndPricingRemittance.class, new ndPricingRemittanceServerAdapter_Servlet());
Pricing.setServerForClass(Pricing.class, new PricingServerAdapter_Servlet());
AccountLength.setServerForClass(AccountLength.class, new AccountLengthServerAdapter_Servlet());
ReorganisationDB.setServerForClass(ReorganisationDB.class, new ReorganisationDBServerAdapter_Servlet());
IntdualcAccount.setServerForClass(IntdualcAccount.class, new IntdualcAccountServerAdapter_Servlet());
IntdualcSettlement.setServerForClass(IntdualcSettlement.class, new IntdualcSettlementServerAdapter_Servlet());
DiSettlement.setServerForClass(DiSettlement.class, new DiSettlementServerAdapter_Servlet());
OrgaDb.setServerForClass(OrgaDb.class, new OrgaDbServerAdapter_Servlet());
}
else ...
Придется опять постить большой кусок текста, который вызовет у Вас недобрые чуйства

public static void setGeneralParameters(J- - - -)
{
String temp;
// set product logo name if available
if ((temp = - -.getParameter("productLogo")) != null)
{
GeneralServerAdapter.setProductLogoForLogonPanel(temp);
Trace.traceInfo("productLogo:"
+ temp);
}
// set client name if available
if ((temp = - -.getParameter("productName")) != null)
{
GeneralServerAdapter.setProductNameForLogonPanel(temp);
Trace.traceInfo("productName:"
+ temp);
}
// trace on/off?
if ((temp = - -.getParameter("Trace")) != null)
Trace.setTraceLevel(Integer.parseInt(temp));
// Security: Is the connection over HTTPS?
if ((temp = - -.getParameter("Security")) != null)
{
GeneralServerAdapter.setSecurityLevel(Integer.parseInt(temp));
Trace.traceInfo("Security level:"
+ temp);
}
// get the https-Port of the server:
if ((temp = - -.getParameter("httpsPort")) != null)
{
GeneralServerAdapter.setSecurityPort(Integer.parseInt(temp));
Trace.traceInfo("https port:"
+ temp);
}
// get the http-Port of the server:
if ((temp = - -.getParameter("httpPort")) != null)
{
GeneralServerAdapter.setHttpPort(Integer.parseInt(temp));
Trace.traceInfo("http port:"
+ temp);
}
if ((temp = - -.getParameter("WriteOutfile")) != null)
{
if (Integer.parseInt(temp) > 0)
{
GeneralBasePanel.setAllowWriteToOutfile(true);
Trace.traceInfo("Write to outfile enabled.");
}
}
// get the http-Port of the server:
if ((temp = - -.getParameter("rmiPort")) != null)
{
GeneralServerAdapter.setRMIPort(Integer.parseInt(temp));
Trace.traceInfo("rmi port:"
+ temp);
}
// get the location of the server
if ((temp = - -.getParameter("HostName")) != null)
{
// if there is a port number in the hostname:
// dismember it and set the separate properties:
int indexOfColon = temp.indexOf(':');
if (indexOfColon >= 0)
{
int port = 0;
if (indexOfColon + 1 < temp.length())
{
port = Integer.parseInt(temp.substring(indexOfColon + 1));
}
// only set the normal http-Port if it isn't set wit "httpPort":
if (GeneralServerAdapter.getHttpPort() <= 0)
{
GeneralServerAdapter.setHttpPort(port);
GeneralServerAdapter.setRMIPort(port);
}
if (indexOfColon > 0)
{
temp = temp.substring(0, indexOfColon);
}
else
{
temp = "";
}
}
GeneralServerAdapter.setHostName(temp);
}
//get the prefix of the servername
if ((temp = - -.getParameter("Product")) != null)
{
GeneralServerAdapter.setProduct(temp);
String stringInstanceNr;
if ((stringInstanceNr = - -.getParameter("Instance")) != null) {
temp = temp + "_" + stringInstanceNr;
}
// this is client side so we can set it globally
GeneralServerAdapter.setGlobalServerNamePrefix(temp + ".");
}
if ((temp = - -.getParameter("Servlet")) != null)
{
c_fServlet = !(temp.equals("0"));
}
//gets the state for the polling mechanism, the default value is true (enabled)
if ((temp = - -.getParameter("Polling")) != null)
{
try
{
c_iPollingOn = (new Integer(temp)).intValue();
}
catch (Exception e)
{
Trace.traceInfo("Error: The defined polling delay is not of type integer !");
c_iPollingOn = 0;
}
}
//is the AccessControl enabled, the default is true!
if ((temp = - -.getParameter("AccessControl")) != null)
{
c_fAccessControllOn = !(temp.equals("0"));
}
//new for JRun 3.1
if ((temp = - -.getParameter("WebApplication")) != null)
GeneralServerAdapter.setWebApplicationMapping(temp);
// Get the ip from the calling client or local host (dev-enviroment)
String ip = "";
// Get IP A: First try over the network interfaces
try
{
Enumeration <NetworkInterface> n = NetworkInterface.getNetworkInterfaces();
outmost:
for (; n.hasMoreElements();)
{
NetworkInterface e = n.nextElement();
Enumeration<InetAddress> a = e.getInetAddresses();
for (; a.hasMoreElements();)
{
InetAddress addr = a.nextElement();
// Anzeige über Messagedialog für Debugging in Citrix-Umgebung (dort ist keine Java-Konsole aktiv)
//JOptionPane.showMessageDialog(null, "HostAddress: " +addr.getHostAddress() + " Hostname: " + addr.getHostName() + " CanonicalHostName: " +addr.getCanonicalHostName());
if (addr instanceof Inet6Address)
{
Trace.traceInfo("Found IP6 Address (IP: " + addr.getHostAddress() + "). Check it...");
// Anzeige über Messagedialog für Debugging in Citrix-Umgebung (dort ist keine Java-Konsole aktiv)
//JOptionPane.showMessageDialog(null, "Found IP6 Address (IP: " + addr.getHostAddress() + "). Check it...");
if (addr.isSiteLocalAddress())
{
Trace.traceInfo("IP6 Address (IP: " + addr.getHostAddress() + ") is a site local address. Search forward...");
// Anzeige über Messagedialog für Debugging in Citrix-Umgebung (dort ist keine Java-Konsole aktiv)
//JOptionPane.showMessageDialog(null, "IP6 Address (IP: " + addr.getHostAddress() + ") is a site local address. Search forward...");
}
else if (addr.isLoopbackAddress())
{
Trace.traceInfo("IP6 Address (IP: " + addr.getHostAddress() + ") is a loopback address. Search forward...");
// Anzeige über Messagedialog für Debugging in Citrix-Umgebung (dort ist keine Java-Konsole aktiv)
//JOptionPane.showMessageDialog(null, "IP6 Address (IP: " + addr.getHostAddress() + ") is a loopback address. Search forward...");
}
else if (addr.isLinkLocalAddress())
{
Trace.traceInfo("IP6 Address (IP: " + addr.getHostAddress() + ") is a link local address. Search forward...");
// Anzeige über Messagedialog für Debugging in Citrix-Umgebung (dort ist keine Java-Konsole aktiv)
//JOptionPane.showMessageDialog(null, "IP6 Address (IP: " + addr.getHostAddress() + ") is a link local address. Search forward...");
}
else
{
Trace.traceInfo("IP6 Address (IP: " + addr.getHostAddress() + " Host: " + addr.getHostName() + ") detected.");
// Anzeige über Messagedialog für Debugging in Citrix-Umgebung (dort ist keine Java-Konsole aktiv)
//JOptionPane.showMessageDialog(null, "IP6 Address (IP: " + addr.getHostAddress() + " Host: " + addr.getHostName() + ") detected.");
ip = addr.getHostAddress();
break outmost;
}
}
if (addr instanceof Inet4Address)
{
Trace.traceInfo("Found IP4 Address (IP: " + addr.getHostAddress() + "). Check it...");
// Anzeige über Messagedialog für Debugging in Citrix-Umgebung (dort ist keine Java-Konsole aktiv)
//JOptionPane.showMessageDialog(null, "Found IP4 Address (IP: " + addr.getHostAddress() + "). Check it...");
if (addr.isSiteLocalAddress())
{
Trace.traceInfo("IP4 Address (IP: " + addr.getHostAddress() + ") is a site local address. Search forward...");
// Anzeige über Messagedialog für Debugging in Citrix-Umgebung (dort ist keine Java-Konsole aktiv)
//JOptionPane.showMessageDialog(null, "IP4 Address (IP: " + addr.getHostAddress() + ") is a site local address. Search forward...");
}
else if (addr.isLoopbackAddress())
{
Trace.traceInfo("IP4 Address (IP: " + addr.getHostAddress() + ") is a loopback address. Search forward...");
// Anzeige über Messagedialog für Debugging in Citrix-Umgebung (dort ist keine Java-Konsole aktiv)
//JOptionPane.showMessageDialog(null, "IP4 Address (IP: " + addr.getHostAddress() + ") is a loopback address. Search forward...");
}
else if (addr.isLinkLocalAddress())
{
Trace.traceInfo("IP4 Address (IP: " + addr.getHostAddress() + ") is a link local address. Search forward...");
// Anzeige über Messagedialog für Debugging in Citrix-Umgebung (dort ist keine Java-Konsole aktiv)
//JOptionPane.showMessageDialog(null, "IP4 Address (IP: " + addr.getHostAddress() + ") is a link local address. Search forward...");
}
else
{
Trace.traceInfo("IP4 Address (IP: " + addr.getHostAddress() + " Host: " + addr.getHostName() + ") detected.");
// Anzeige über Messagedialog für Debugging in Citrix-Umgebung (dort ist keine Java-Konsole aktiv)
//JOptionPane.showMessageDialog(null, "IP4 Address (IP: " + addr.getHostAddress() + " Host: " + addr.getHostName() + ") detected.");
ip = addr.getHostAddress();
break outmost;
}
}
}
}
} catch (SocketException e) {
Trace.traceException(e);
Trace.traceStack();
}
// Get IP B: Second try over Socket
if ( ip.isEmpty() )
{
Socket socket = null;
int port = 0;
if(- -.getDocumentBase().getPort()!=-1)
{
port = - -.getDocumentBase().getPort();
}
else
{
port = 80;
}
try
{
socket = new Socket(- -.getDocumentBase().getHost(), port);
if (socket != null)
{
ip = socket.getLocalAddress().getHostAddress();
}
} catch (UnknownHostException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
// Check ip - is loopback ip?
if ( ip.isEmpty() || "127.0.0.1".equals(ip) )
{
Trace.traceInfo("Cannot determine local IP address !");
ip = "0.0.0.0";
Trace.traceInfo("Use default ip: " + ip );
}
Current- -Context.setC_local_ip(ip);
// now we have to define the mapping between some client personality classes and their
// corresponding adapter classes (the ones which are used in this base class)
if (isServletCommunication())
{
Trace.traceInfo("Use Servlet Communication ...");
Authentication.setServerForClass(Authentication.class, new AuthenticationServerAdapter_Servlet());
}
else
{
Trace.traceInfo("Use RMI Communication ...");
Authentication.setServerForClass(Authentication.class, new AuthenticationServerAdapter_RMI());
}
if ((temp = - -.getParameter("DefaultTimeZone")) != null)
GeneralServerAdapter.setDefaultTimeZone(temp);
if ((temp = - -.getParameter("ShellTimezone")) != null)
{
CurrentDateSupport.setTimeSupport(temp);
}
Trace.traceInfo("set param ShellTimezone: "
+ CurrentDateSupport.getTimeSupport());
}
Апплет у вас как-то идентифицируется, несмотря на то что общение с сервером идет в одной сессии, или нет?
Т.е. если на одной машине открыты два окна, в обоих юзер залогинится используя один и тот же логин X, на сервлет пришел какой-то запрос, вы можете понять от какого из двух апплетов он пришел?
Очевидно, нет, если IP один и тот же.
Но обычно юзер логинится под двумя разными аккаунтами, под одним не имеет смысла.
Большое спасибо за конкретное предложение

Мне надо сделать обеденную паузу и подумать над ним.
Хммм... Эквивалентно - Едя по автобану на Юг мы пешком по буеракам идем север.
В каком же направлении движение то?
Я надеюсь, из приведенного выше кода это стало немного понятно?
Там даже про сокеты есть.
У вас в классе AuthenticationData хранится локальный IP-адрес. Наверное, в этом AuthenticationData у вас и имя пользователя и пароль в каком-то виде хранится. Только это не говорит о том что у вас на томкате сессия по ип выдается.
Вангую: у апплета есть метод который вызывает sendRequest(Object) и передает кму как параметр объект типа AuthenticationData. Это и есть метод для логина.
Как у вас сконфигурирован Manager в Context-е?
Я имел в виду томкат, где ваш deployment descriptor для вашего сервлета. Ищите context.xml
Вы же мне накидали класс, который у вас в буфере объекты хранит.
public synchronized InputStream sendRequest(Serializable obj) throws Throwable
Это не
код сервлета, который вызывается когда пользователь логинится.
Это код апплета, которым он связывается с сервлетом.
setGeneralParameters тоже похож на код апплета. На мои вопросы не отвечает.
Вы знаете, вы похоже думаете, что вы накидаете куски кода а вам - раз и выложат решение. Это вряд ли. Прошла неделя а вы так и не удосужились разобраться где же у вас сервлет, где апплет а где томкат с сессией.
Подсказать направление я вам могу, а за вас делать меньше сотни за час не возьму.
Две подсказки:
- у вас нет никакой HttpSession на томкате. Вы с сервлетом по URLConnection общаетесь, куки не передаете, ;jsessionid к URL не приписываете, из InputStream-а кукине читаете.
- код вашего сервлета ищите в классе, который extends HttpServlet
------
Нее, не на много.
Пока понятно что у тебя либо дуальная - <HTTP & RMI> или потенциально дуальная коммуникация с сервером.
Когда и какая - надо смотреть... Проимплементил бы фабрику коммуникаторов - понимать было бы легче.
Одно ясно - не чисто <HTTP(S)>.
-----
У меня ощущение, что у него нет доступа к этой части. Есть какой-то самописный <rmi-2-http> прокси и на этом все - дальше не пускают.
где же у вас сервлет, где апплет а где томкат с сессией.
-----
Хи-хи-кс...

Только это не говорит о том что у вас на томкате сессия по ип выдается.
Я у шефа спрашивал, он сказал, что 100% по IP

Да и как еще, если всегда одна сессия на рыло?
Вангую: у апплета есть метод который вызывает sendRequest(- -) и передает кму как параметр объект типа AuthenticationData. Это и есть метод для логина.
Ванговать не надо, sendRequest(- -) у меня выше описан

Вызывается он с объектом типа ServletTransfer- -.
Я имел в виду томкат, где ваш deployment de- -or для вашего сервлета. Ищите context.xml
Есть, но он практически пустой:
less server.xml
<Server port="18160" shutdown="SHUTDOWN" debug="0">
<Listener className="org.apache.catalina.mbeans.ServerLifecycleListener"
debug="0"/>
<Listener className="org.apache.catalina.mbeans.GlobalResourcesLifecycleListener"
debug="0"/>
<GlobalNamingResources>
<Context className="org.apache.catalina.core.StandardContext"
cachingAllowed="true"
charsetMapperClass="org.apache.catalina.util.CharsetMapper"
cookies="true"
crossContext="false"
debug="0"
displayName="ICM-6 Entwicklung"
docBase="/home/icm6/dcc/web/lib"
mapperClass="org.apache.catalina.core.StandardContextMapper"
path="/ICM6"
privileged="true"
reloadable="true"
swallowOutput="false"
useNaming="true"
wrapperClass="org.apache.catalina.core.StandardWrapper">
<Resources className="org.apache.naming.resources.FileDirContext"
allowLinking="true" />
</Context>
</Host>
</Engine>
</Service>
</Server>
setGeneralParameters тоже похож на код апплета. На мои вопросы не отвечает.
Код public class ndServlet extends HttpServlet ниже, а здесь сначала еще один класс, который этим занимается:
public class GeneralServerAdapter_Servlet extends GeneralServerAdapter
implements IGeneralServerAdapter
{
private URL m_servlet = null;
..........
/**
* Special method to return the result data of the request.
*
* This is handled in a separate method to support advanced communication
* issues like e.g. multi block data transfer.
*/
protected - - getResultData(ServletTransfer- - reqObj,
ServletTransfer- - resObj) throws GeneralException
{
- - obj = resObj.getData- -();
// if there is a special communication - - returned
// -> this is a multi block data transfer
if (obj == null)
return (obj);
if (!(obj instanceof ndCommunication- -))
return (obj);
// special communication required - multi block data transfer
ndCommunication- - ndComm = (ndCommunication- -)obj;
// The result we receive can take two different forms:
// - a normal vector, which contains data elements and we
// have to append following data blocks to this vector
// - a special vector containing exactly two elements
// -> a de- -ion - -
// -> a data vector (where we have to append the following data)
- - objResult = ndComm.getData();
Assertion.verify(objResult instanceof Vector<?>);
Vector<?> vecResult = (Vector<?>) objResult;
// locate the relevant data vector to which we will add the following
// data blocks
@SuppressWarnings("unchecked")
Vector<- -> vecReceivedData = (Vector<- ->) vecResult;
// if the result vector as two elements and the second element is a vector
// the "real" result is the second element
if ((vecResult.size() == 2) && (vecResult.elementAt(1) instanceof Vector<?>))
{
@SuppressWarnings("unchecked")
Vector<- -> realResultVec = (Vector<- ->) vecResult.elementAt(1);
vecReceivedData = realResultVec;
}
// NOTE: if we now add data to vecReceivedData, we add it indirectly either
// to vecResult (in case vecResult is the "real" data vector) or to
// the second element of vecResult (in case the second element is the
// "real" data vector)
// prepare the special transfer - - to communicate with the servlet
reqObj.setAdapterMethod("getNextDataBlock");
reqObj.setArgumentClass(ndComm.getClass().getName());
while (ndComm.isMoreDataAvailable())
{
// read the next data block
reqObj.setData- -(ndComm);
ndComm.setDataCompressed(false);
ndComm.setData(null);
resObj = (ServletTransfer- -)doRequest(reqObj);
if (resObj.getException() != null)
throw resObj.getException();
obj = resObj.getData- -();
// append data of the current block to the result vector
Assertion.verify(obj instanceof ndCommunication- -);
ndComm = (ndCommunication- -)obj;
Vector<?> vecNewData = (Vector<?>) ndComm.getData();
VectorSupport.addAllFrom(vecNewData, vecReceivedData);
}
return vecResult;
}
public synchronized - - doRequest(ServletTransfer- - obj)
throws GeneralException
{
// the method is synchronized for this - - which means there can only
// be one request via this - - at a time
// -> but to be sure that there is only one request at a time from
// -> the virtual machine (from the Client) we synchronize
// -> via a static - -
- - objResult = null;
synchronized(c_fSyncSendRequest)
{
try
{
getServlet();
// Send the request
// sometimes there occurs an IOException in IE context so we'll
// try it several times
int iTries = 1;
boolean fOk = false;
InputStream in = null;
while (!fOk)
{
try
{
iTries++;
in = sendRequest(obj);
fOk = true;
}
catch (IOException ex)
{
// we allow three tries...
if (iTries >= 3)
throw ex;
Trace.traceInfo("IOException occurred - try again...");
}
}
// now get the result
- -InputStream result = new - -InputStream(in);
// and build the result - -
objResult = result.read- -();
in.close();
m_connection = null;
}
catch (Throwable e)
{
...
}
}
return (objResult);
}
public URL getServlet() throws GeneralException
{
// if it is already there - use it - but only if security hasn't changed...
if (m_servlet != null && m_iLastSecurityLevel == getCurrentServletSecurityLevel())
{
return (m_servlet);
}
// try to get the servlet
try
{
showInfo("Servlet-Name: " + getServletName());
m_servlet = new URL(getServletName());
m_iLastSecurityLevel=getCurrentServletSecurityLevel();
}
catch (Throwable e)
{
m_servlet = null;
throw new GeneralException(e);
}
return (m_servlet);
}
public synchronized InputStream sendRequest(Serializable obj) throws Throwable
{
showInfo("Open connection to servlet: " + m_servlet.toString());
m_connection = m_servlet.openConnection();
// Prepare for both input and output
m_connection.setDoInput(true);
m_connection.setDoOutput(true);
// Turn off caching
m_connection.setUseCaches(false);
// Set the content type to be java-internal/classname
m_connection.setRequestProperty("Content-Type",
"java-internal/" + obj.getClass().getName());
// Write the serialized - - as post data
- -OutputStream out = new - -OutputStream(m_connection.getOutputStream());
out.write- -(obj);
out.flush();
out.close();
return m_connection.getInputStream();
}
Вы знаете, вы похоже думаете, что вы накидаете куски кода а вам - раз и выложат решение.
Нет, я так не думаю. Вы меня просили показать код, я показал. Ну, ошибся разок, извините.
Прошла неделя
Еще не прошла. Я только в пятницу открыл ветку
Учтите, что я в этом деле профан и иду, как по минному полю.
Подсказать направление я вам могу, а за вас делать меньше сотни за час не возьму.
Направление мне и надо.
Две подсказки:
- у вас нет никакой HttpSession на томкате.
Да, видимо, это верно. Я покопался в логах томката, никакой HttpSession там не нашел. В коде она есть, в том самом пакете Servlet и классе ndServlet extends HttpServlet:
* The ndServlet class provides transport functionality from the client
* side to the RMI-server.
*
* @version 1.00 03.12.1999
* @see HttpServlet
*/
public class ndServlet
//Process the HTTP Post request
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException
{
HttpSession session = request.getSession(true);
showInfo("session got: " + session.getId());
if (session.getAttribute(KEY_BINDING_LISTENER) != this)
session.setAttribute(KEY_BINDING_LISTENER, this);
else
showInfo("ndServlet.doPost, getAttribute(KEY_BINDING_LISTENER) <> this");
public void init(ServletConfig config) throws ServletException
{
super.init(config);
String hostname;
String maxBlockSize;
int tracelevel;
//In the Moment, we set no Security! It remains to check, if you can do it with policy-files
//System.setSecurityManager(new NoSecurityManager());
// Trace on/off?
if (config.getInitParameter("Trace") != null)
{
tracelevel = Integer.parseInt(config.getInitParameter("Trace"));
if ((tracelevel > Trace.TRACE_OFF) &&
(tracelevel <= Trace.FUNCTION_TRACE))
Trace.setTraceLevel(tracelevel);
}
showInfo("ndServlet.init: init called ...");
// set the server for the RMI-Communication
if ((hostname = config.getInitParameter("HostName")) != null)
{
GeneralServerAdapter.setHostName(hostname);
showInfo("hostname for RMI set to: " + hostname);
}
// enable own support for communication
if (config.getInitParameter("HandleCommunication") != null)
{
String str = config.getInitParameter("HandleCommunication");
boolean fEnable = (Integer.parseInt(str) != 0);
c_fSpecialCommunicationSupport = fEnable;
if (fEnable)
showInfo("Special support for communication enabled");
}
// handle special parameters for special communication (if this is enabled)
if (c_fSpecialCommunicationSupport)
{
// set the max transfer block size
if ((maxBlockSize = config.getInitParameter("TransferBlockSize")) != null)
{
setMaxTransferBlockSize(Integer.parseInt(maxBlockSize));
}
showInfo("Transfer block size: " + c_iMaxBlockSize);
// enable compression for data transfer if requested
if (config.getInitParameter("TransferCompression") != null)
{
String str = config.getInitParameter("TransferCompression");
boolean fEnable = (Integer.parseInt(str) != 0);
setUseCompressionForTransfer(fEnable);
if (fEnable)
showInfo("Compression activated for transfer");
else
showInfo("Compression deactivated for transfer");
}
}
}
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException
{
showInfo("doGet called...");
}
public void service(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException
{
super.service(req, resp);
}
//Process the HTTP Post request
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException
{
try
{
AnalyzeSupport timeSup = new AnalyzeSupport();
showInfo("doPost started");
// first get the request - -
- -InputStream objIn = new - -InputStream(request.getInputStream());
ServletTransfer- - objTransfer = (ServletTransfer- -)objIn.read- -();
objIn.close();
- - objResult;
// now handle special case: multi block transfer
// (in case of own support for communication)
if (!(objTransfer.getData- -() instanceof ndCommunication- -) ||
!c_fSpecialCommunicationSupport)
{
// now fulfill the request which is described in the transfer - -
// -> first build the requested instance
Class<?> clsAdapter = Class.forName(objTransfer.getAdapterClass());
- - objAdapter = clsAdapter.newInstance();
// -> and then call the method to get the result
Class<?> paramClasses[] = null;
- - params[] = null;
if (objTransfer.getData- -() != null)
{
paramClasses = new Class[1];
paramClasses[0] = Class.forName(objTransfer.getArgumentClass());
params = new - -[1];
params[0] = objTransfer.getData- -();
}
Method met = clsAdapter.getMethod(objTransfer.getAdapterMethod(), paramClasses);
// set binding listener for session if it's not already done...
HttpSession session = request.getSession(true);
showInfo("session got: " + session.getId());
if (session.getAttribute(KEY_BINDING_LISTENER) != this)
session.setAttribute(KEY_BINDING_LISTENER, this);
else
showInfo("ndServlet.doPost, getAttribute(KEY_BINDING_LISTENER) <> this");
// save the Prefix to be used for server communication from this servlet
setServerNamePrefix(objTransfer.getServerNamePrefix());
if (objAdapter instanceof GeneralServerAdapter)
{
GeneralServerAdapter adapt = (GeneralServerAdapter)objAdapter;
adapt.setServerNamePrefix(this.getServerNamePrefix());
}
// set current sessionid in Adapter as the access key
if (objAdapter instanceof GeneralServerAdapter_RMI)
{
GeneralServerAdapter_RMI adapt = (GeneralServerAdapter_RMI)objAdapter;
adapt.setAccessKey(session.getId());
showInfo("ndServlet.doPost, SessionID(access key) set: " + session.getId());
// also use the session id as request id
adapt.setRequestId(session.getId());
// the adapter should handle special communication issues
// in case the servlet should also do it on its own
adapt.setHandleSpecialCommunication(c_fSpecialCommunicationSupport);
}
AnalyzeSupport timeSup2 = new AnalyzeSupport();
showInfo("ndServlet.doPost, Method: " + met.getName());
objResult = met.invoke(objAdapter, params);
timeSup2.showTimeUsage("ndServlet.doPost RMI-Invocation-Time:");
}
else
{
// special communication
showInfo("getNextDataBlock...");
objResult = this.getNextDataBlock((ndCommunication- -)objTransfer.getData- -());
}
if (objResult != null)
{
// now build the response - -
objTransfer.setData- -((Serializable)this.getResult- -(objResult));
// ...and send it back to the requestor
response.setContentType("java-internal/" + objResult.getClass().getName());
}
else
{
objTransfer.setData- - (null);
response.setContentType("java-internal/null");
}
// now write the - - to the response output stream
this.write- -(response, objTransfer);
timeSup.showTimeUsage("PP_Servlet Request-Time:");
}
catch (Throwable e)
{
GeneralException ex;
if (e instanceof GeneralException)
ex = (GeneralException)e;
else
ex = new GeneralException(e);
// ...and send it back to the requestor
response.setContentType("text/html");
ServletTransfer- - objTransfer = new ServletTransfer- -();
objTransfer.setData- -(new Vector<- ->());
objTransfer.setException(ex);
// now write the - - to the response output stream
this.write- -(response, objTransfer);
}
}
/**
* Special handling for returning the result - -
* created for the current request.
*/
protected - - getResult- -(- - result) throws GeneralException
{
boolean fCachedSearch = false;
boolean fVectorResult = false;
Vector<- -> vecResult = new Vector<- ->();
if (result == null) {
return (result);
}
// if the servlet is advised not to do its own
// communication we return the result - - directly
// (in case of a vector we look for a ndCommunication- - as only
// element and return this)
if (!c_fSpecialCommunicationSupport)
{
if (result instanceof Vector<?>)
{
Iterator<?> iterator = ((Vector<?>) result).iterator();
while (iterator.hasNext()) {
vecResult.add((- -)iterator.next());
}
if (vecResult.size() == 1)
{
- - obj1 = vecResult.firstElement();
if (obj1 instanceof ndCommunication- -) {
return (obj1);
}
}
}
return (result);
}
// if this is a special search the result - - is a vector
// which contains two elements:
// 1. GeneralSearchDe- -ion- - (to describe the search)
// 2. Vector (result data)
if (result instanceof Vector<?>)
{
Iterator<?> iterator = ((Vector<?>) result).iterator();
while (iterator.hasNext()) {
vecResult.add((- -)iterator.next());
}
fVectorResult = true;
if (vecResult.size() == 2)
{
- - obj1 = vecResult.firstElement();
- - obj2 = vecResult.elementAt(1);
if ( (obj1 instanceof GeneralSearchDe- -ion- -)
&& (obj2 instanceof Vector<?>))
{
fCachedSearch = true;
}
}
}
// now in case of returning a vector we have to check the size
// against the given block size to support the transfer of
// large vectors in multiple data blocks
// -> this approach only makes sense for external requests due to
// -> slow data transfer...
if ((c_iMaxBlockSize > 0) && fVectorResult)
{
if (fCachedSearch)
{
Vector<?> vecData = (Vector<?>) vecResult.elementAt(1);
if (vecData.size() > c_iMaxBlockSize)
{
// in this case the second element (the data vector) has to be
// replaced by a vector containing the first data block of this vector
Vector<- -> vecNewData = new Vector<- ->();
// multi block transfer is necessary
// -> we have to encapsulate the data in a special communication
// -> - - which has to be used for these purposes
ndCommunication- - ndComm = new ndCommunication- -();
ndComm.setAccessKey(VectorStore.addVector(vecData));
ndComm.setMoreDataAvailable(VectorStore.getNextBlockFromVector(ndComm.getAccessKey(),
vecNewData,
c_iMaxBlockSize));
// fill in the new data block in the result vector
vecResult.removeElementAt(1);
vecResult.addElement(vecNewData);
ndComm.setDataCompressed(c_fUseCompressionForTransfer);
ndComm.setData(vecResult);
result = ndComm;
}
}
else
{
if (vecResult.size() > c_iMaxBlockSize)
{
// multi block transfer is necessary
// -> we have to encapsulate the data in a special communication
// -> - - which has to be used for these purposes
ndCommunication- - ndComm = new ndCommunication- -();
ndComm.setAccessKey(VectorStore.addVector(vecResult));
Vector<- -> vecData = new Vector<- ->();
ndComm.setMoreDataAvailable(VectorStore.getNextBlockFromVector(ndComm.getAccessKey(),
vecData,
c_iMaxBlockSize));
ndComm.setDataCompressed(c_fUseCompressionForTransfer);
ndComm.setData(vecData);
result = ndComm;
}
else if (c_fUseCompressionForTransfer)
{
// -> we have to encapsulate the data in a special communication
// -> - - which has to be used for these purposes (compression)
ndCommunication- - ndComm = new ndCommunication- -();
Vector<- -> vecData = vecResult;
ndComm.setDataCompressed(c_fUseCompressionForTransfer);
ndComm.setData(vecData);
result = ndComm;
}
}
}
// compress vector results on request
else if (fVectorResult && c_fUseCompressionForTransfer)
{
// -> we have to encapsulate the data in a special communication
// -> - - which has to be used for these purposes (compression)
ndCommunication- - ndComm = new ndCommunication- -();
Vector<- -> vecData = vecResult;
ndComm.setDataCompressed(c_fUseCompressionForTransfer);
ndComm.setData(vecData);
result = ndComm;
}
return (result);
}
/**
* Special method to handle multi block data transfer - this method
* fetches the next data block which is part of a vector.
*/
protected ndCommunication- - getNextDataBlock(ndCommunication- - ndComm) throws GeneralException
{
Vector<?> vecData = new Vector<- ->();
ndComm.setMoreDataAvailable(VectorStore.getNextBlockFromVector(ndComm.getAccessKey(),
vecData,
c_iMaxBlockSize));
ndComm.setDataCompressed(c_fUseCompressionForTransfer);
ndComm.setData(vecData);
return (ndComm);
}
...
И этот класс ndServlet вызывается в том коде, который я Вам показал выше, но только 1 раз:
GeneralServerAdapter_Servlet.setDefaultServletClass(ndServlet.class);
В остальном он используется только для репортов.
куки не передаете
Ява-консоль пишет, что соединение с куками:
network: Connecting http://.../servlet.jar with cookie
network: Connecting http:/.../jakarta-oro-2.0.jar with cookie
security: Checking if certificate is in Deployment session certificate store
security: Checking if SSL certificate is in Deployment permanent certificate store
security: Possible use of Secure cookies blocked for
security: To use secure cookie (HTTPS), consider signing the application or host application with HTTPS
security: Possible use of Secure cookies blocked for https://.../servlet/de.novadata.pp.servlet.ndServlet
network: Connecting http://.../servlet/de.novadata.pp.servlet.ndServlet with cookie "JSESSIONID=A4C73477D9C1B454F601463D8C5F07A1"
Но у себя на компе я ни одного куки на эту темку не нашел
Я у шефа спрашивал, он сказал, что 100% по IP
И 100% томкатовская HttpSession? Эт врядли.
Да и как еще, если всегда одна сессия на рыло?
Легко и ненапряжно 100500-ми способами. Кто ж знает что у вас используется, ни кода ни конфигурации я пока что не увидел.
Ванговать не надо, sendRequest(- -) у меня выше описан Как и про пароль с логином.
ну так посмотрите на этот метод, который вызывает sendRequest и передает ему пароль с логином. Может это User.logon(...) делает? Или все работает исключительно через GeneralServerAdapter_Servlet.doRequest(ServerTransferObject)?
Это будет сторона клиента (апплета) Мне интересно что происходит на стороне сервера (сервлета).
sendRequest посылает данные на URL, который хранится в поле m_servlet. Проверьте что именно этот метод используется для общения с сервлетом. С каким URL-ем он открывает соединение? Что именно шлет серверу? Дебаггер или просто систем.аутов понапихайте.
У сервлета должен вызываться метод doPost(...)
Найдите у себя класс, который extends HttpServler (или у вас своя реализация интерфейса Servlet? тогда implements Servlet) и посмотрите что же он делает c входящими данными.
Может, у вас как-то кусками копируется текст, и ndServlet все же extend HttpServlet? Еще раз спрашиваю - вы вообще смотрите что и как вставляете? Это же понять невозможно... ndServlet.doPost оборвался в середине метода. Что происходит после
if (session.getAttribute(KEY_BINDING_LISTENER) != this)
session.setAttribute(KEY_BINDING_LISTENER, this);
else
showInfo("ndServlet.doPost, getAttribute(KEY_BINDING_LISTENER) <> this");
У вас в логи выводится session got: xxxxxxx (на 01.09.2015 12:27:23 DCC_4 (25) I: request for access key: 540C407B5B9122D19AFC1588C2A49579 не похоже) из
showInfo("session got: " + session.getId());
?
Какой там ID? Постоянно при каждом запросе тот же самый?
P.S. Вставляйте код в тэги [pre][/pre]
Тебе Мурр и Сандерс верно написали - нет решения на клиенте - только на сервере.
Что у тебя за серверное ява-приложение - м б какой фреймворк стоит что то вроде спринга или гвт или что другое.
Вообще раскрой подробно задачу - ибо те объемы кода что ты постишь как то ни фига на решение не похоже. Почти в любом норм. ява фреймворке есть стандартное управление сессиями.
А не то что ты нагородил.
Как сишник не подскажешь решение проблемки
http://foren.germany.ru/postlist.pl?Cat=&Board=programmer&page=0&view=collapsed&...
Кстати чего в диполе не появляешься? устал от ....даков аленей и курбанов с лешиками и юнонками? (пты и мой оппонент)
Кстати чего в диполе не появляешься?
Во-первых, хамства не люблю, типа вот этого:
несусветное наворотил
нагородил
Во-вторых, больше мне делать нечего, как с ДК-шными модерами-ублюдками бодаться, да плюс к тому еще с "добровольными помощниками милиции" вроде отсоса Курбана, ты его с его гнилой "аргументацией" вежливо мокнул, а он с помощью своей подружки-училки тут же натянул на себя презик Модератора1 и в бан тебя на неделю. Такого маразма даже на ДК в его худшие времена не бывало.
Вообще раскрой подробно задачу - ибо те объемы кода что ты постишь как то ни фига на решение не похоже.
Задачу я давно уже раскрыл, кроме тебя все ее тут давно уже поняли.
Код я пощу, когда просят.
Никаких решений я этим кодом не предлагал, это уже имеющийся код, а если б у меня было решение, я б сюда не полез, короче, сначала разберись, потом помогай

Как сишник не подскажешь решение проблемки
http://foren.germany.ru/postlist.pl?Cat=&Board=programmer&page=0&view=collapsed&...
Доска "Программирование" является для тебя проблемкой?

Как то так делается
public String getIpAddress(String host) {
try {
ifcfg = NetworkInterface.getByName(host);
addresses = ifcfg.getInetAddresses();
while (addresses.hasMoreElements()) {
address = addresses.nextElement().toString();
address = address.replace("/", "");
}
} catch (Exception e) {
e.printStackTrace();
}
return ifcfg.toString();
}
И дальше сравнивай с IP уже зашедших юзеров
http://foren.germany.ru/programmer/f/28923558.html?Cat=&page=0&view=collapsed&sb...
мой вопрос
Легко и ненапряжно 100500-ми способами. Кто ж знает что у вас используется, ни кода ни конфигурации я пока что не увидел.
Не понял. Я ведь запостил код сервлета, который Вы просили, а что еще надо?
ну так посмотрите на этот метод, который вызывает sendRequest и передает ему пароль с логином. Может это User.logon(...) делает?
Это doRequest(ServletTransfer- - obj) делает.
Или все работает исключительно через GeneralServerAdapter_Servlet.doRequest(ServerTransfer- -)?
Да.
Это будет сторона клиента (апплета) Мне интересно что происходит на стороне сервера (сервлета).
sendRequest посылает данные на URL, который хранится в поле m_servlet. Проверьте что именно этот метод используется для общения с сервлетом. С каким URL-ем он открывает соединение? Что именно шлет серверу? Дебаггер или просто систем.аутов понапихайте.
Да, пришлось понапихать, поскольку Эклипс с сервлетом не работает:
m_servlet2: http://sv........com:8160/ICM6/servlet/de.novadata.pp.servlet.ndServlet
in = sendRequest(obj);
System.out.println("doRequest2: doRequest: " + in):
doRequest2: doRequest: sun.net.www.protocol.http.HttpURLConnection$HttpInputStream@396c7
System.out.println("doRequest3: doRequest: " + obj);
doRequest3: doRequest: de.novadata.pp.base- -s.ServletTransfer- -@5f3bad
У сервлета должен вызываться метод doPost(...)
Дык и вызывается:
showInfo("ndServlet.doPost, getAttribute(KEY_BINDING_LISTENER) <> this");
Найдите у себя класс, который extends HttpServler (или у вас своя реализация интерфейса Servlet? тогда implements Servlet) и посмотрите что же он делает c входящими данными.
Нет, extends, я ж постил уже:
public class ndServlet extends HttpServlet implements SingleThreadModel,
HttpSessionBindingListener
Может, у вас как-то кусками копируется текст, и ndServlet все же extend HttpServlet? Еще раз спрашиваю - вы вообще смотрите что и как вставляете? Это же понять невозможно... ndServlet.doPost оборвался в середине метода. Что происходит после
if (session.getAttribute(KEY_BINDING_LISTENER) != this)
session.setAttribute(KEY_BINDING_LISTENER, this);
else
showInfo("ndServlet.doPost, getAttribute(KEY_BINDING_LISTENER) <> this");
Привожу конец эту методу с этого места и до конца:
if (session.getAttribute(KEY_BINDING_LISTENER) != this)
session.setAttribute(KEY_BINDING_LISTENER, this);
else
showInfo("ndServlet.doPost, getAttribute(KEY_BINDING_LISTENER) <> this");
// save the Prefix to be used for server communication from this servlet
setServerNamePrefix(objTransfer.getServerNamePrefix());
if (objAdapter instanceof GeneralServerAdapter)
{
GeneralServerAdapter adapt = (GeneralServerAdapter)objAdapter;
adapt.setServerNamePrefix(this.getServerNamePrefix());
}
// set current sessionid in Adapter as the access key
if (objAdapter instanceof GeneralServerAdapter_RMI)
{
GeneralServerAdapter_RMI adapt = (GeneralServerAdapter_RMI)objAdapter;
adapt.setAccessKey(session.getId());
showInfo("ndServlet.doPost, SessionID(access key) set: " + session.getId());
// also use the session id as request id
adapt.setRequestId(session.getId());
// the adapter should handle special communication issues
// in case the servlet should also do it on its own
adapt.setHandleSpecialCommunication(c_fSpecialCommunicationSupport);
}
AnalyzeSupport timeSup2 = new AnalyzeSupport();
showInfo("ndServlet.doPost, Method: " + met.getName());
objResult = met.invoke(objAdapter, params);
timeSup2.showTimeUsage("ndServlet.doPost RMI-Invocation-Time:");
}
else
{
// special communication
showInfo("getNextDataBlock...");
objResult = this.getNextDataBlock((ndCommunication- -)objTransfer.getData- -());
}
if (objResult != null)
{
// now build the response - -
objTransfer.setData- -((Serializable)this.getResult- -(objResult));
// ...and send it back to the requestor
response.setContentType("java-internal/" + objResult.getClass().getName());
}
else
{
objTransfer.setData- - (null);
response.setContentType("java-internal/null");
}
// now write the - - to the response output stream
this.write- -(response, objTransfer);
timeSup.showTimeUsage("PP_Servlet Request-Time:");
}
catch (Throwable e)
{
GeneralException ex;
if (e instanceof GeneralException)
ex = (GeneralException)e;
else
ex = new GeneralException(e);
// ...and send it back to the requestor
response.setContentType("text/html");
ServletTransfer- - objTransfer = new ServletTransfer- -();
objTransfer.setData- -(new Vector<- ->());
objTransfer.setException(ex);
// now write the - - to the response output stream
this.write- -(response, objTransfer);
}
}
У вас в логи выводится session got: xxxxxxx (на 01.09.2015 12:27:23 DCC_4 (25) I: request for access key: 540C407B5B9122D19AFC1588C2A49579 не похоже) из
showInfo("session got: " + session.getId());
Тут я сначала херню написал, прошу пардонов.
Просто это место на консоль не выводится, но есть в томкатовском логе:
05.09.2015 02:57:25 I: PP_Servlet (02:57:25):ndServlet.doPost, Method: getAttentionLogs
at de.novadata.pp.servlet.ndServlet.doPost(ndServlet.java:231)
05.09.2015 02:57:38 I: PP_Servlet (02:57:38):ndServlet.doPost, getAttribute(KEY_BINDING_LISTENER) <> this
05.09.2015 02:57:38 I: PP_Servlet (02:57:38):ndServlet.doPost, SessionID(access key) set: 10C7257FBFB48F1755DDEC4A20194520
System.out.println("session got: " + session.getId());
09.09.2015 16:59:27 I: PP_Servlet (16:59:27):session got: 596099E13516A03E708161FEE9B16F99
session got: 596099E13516A03E708161FEE9B16F99
P.S. Cлово "<\Object>" тут почему-то не перевариваривается из него делается "- -". Там, где эта фигня встречается, надо читать ее как <Обжект>. \[/pre] тоже где-то выполняется, где-то нет.
Я ведь запостил код сервлета, который Вы просили, а что еще надо?
Пока что в этих кусках кода не видно где же какое-то нестандартное поведение с сессией происходит.
Давайте так, я вам коротенько расскажу как обычно томкат работает с HttpSession.
1. Клиент запрашивает url http://myserver.com/myservlet
2. Http сервер передает запрос томкату (ну или сам томкат слушает 80-й порт).
3. Томкат смотрит - есть ли у запроса идентификатор сессии. Это или куки JSESSIONID или дополнение к URL, который выглядит тогда как http://myserver.com/myservlet;jsessionid=abcd1234
4. Если идентификатора нет, томкат создает новую сессию. Генерирует для нее ID и создает новый объект HttpSession. Если идентификатор и для него существует сессия, томкат берет cуществующий HttpSession
Томкат может поменять id сессии, в зависимости от настроек.
5. Томкат отвечат на запрос и передает ID текущей сессии или как куки в заголовке ответа "Set-Cookie" или переписывая все ссылки в ответе, добавляя к ним ;jsessionid=<текущий ID>
6. Клиент или сохраняет куки или просто использует переписанные ссылки.
N.B. Кстати, а посмотрите в каком месте в вашем коде пишется в лог "DCC_4 (25) I: request for access key: 540C407B5B9122D19AFC1588C2A49579". Узнаете откуда берется этот ID.
Вы уверены что общение с сервлетом идет через doRequest(ServletTransferObject). В этом методе не делается ничего чтобы передать томкату инормацию о сессии. Ни куки в заголовок не добавляются, ни ;jsessionid с текущим ID сессии. Из ответа новый JSESSIONID тоже не считывается. "Автоматически" это не происходит.
Итого. По увиденному коду я ожидаю новую HttpSession на томкате, каждый раз, когда на сервлет приходит запрос.
Если вы в данный момент отличать запущенные на одном компе копии апплета не можете, сделайте следующее:
1. При запуске апплета (в init-е) генерируйте MD5 хэш. Например из текущего времени и еще чего-нибудь случайного.
2. Расширьте ServlerTransferObject: добавьте поле appletId, в которое перед отравкой на сервер будете вписывать ид апплета.
3. На сервере в doPost читаем этот ID из запроса. Профит. Он и будет uniqueClientId из моего предыдущего примера.
Да, чтобы найти где же у вас конфигурация для ndServet-а поищите в вашем проекте или в томкатовском каталоге, куда сервлет деплоится, файл web.xml в котором содержатися параметры сервера "HostName", "HandleCommunication" и т.п. (см. код ndServlet.init(ServletConfig)). Выглядит это примерно так:
<init-param>
<param-name>HostName</param-name>
<param-value>a.b.com</param-value>
</init-param>
P.S. Совет - чтбы написать ругательные слова Object, script, applet, пишите их как Obje[i][/i]ct. Тогда движок их не находит и не выбрасывает.
1. При логине смотрим в HttpSession (метод getAttribute(String))- есть ли у нас аттрибут CURRENT_LOGIN
1.1 нет аттрибута. Значит в этой сессии никто не залогинен. Разрешаем логин
session.setAttribute("CURRENT_LOGIN", uniqueClientId);
session.setAttribute("LAST_ACTION_TIME", System.currentTimeMillis());
1.2 есть аттрибут. Проверяем не вылетел ли этот пользоватль по таймауту. Читаем из сессии LAST_ACTION_TIME
[/pre]
Получилось вот что. Он вызывает сервлет несколько раз - только для одного окна.
Я ставлю атррибут, в качестве uniqueClientId использую идентификатор сессии, это длинное 16ричное число, которое Вы видели (это ничто иное как obj.getAccessKey() = accessKey из класса ndRMIRequest- - implements Serializable).
И вот какая штука: он все время говорит, что аттрибута нет!
09.09.2015 19:13:50
session got: F73F2838299E3E9088ECE0B56C5D798C
localIP0:
current_login is NULL
.......
09.09.2015 19:13:50
session got: F73F2838299E3E9088ECE0B56C5D798C
localIP0:
current_login is NULL
......
09.09.2015 19:14:20 I: PP_Servlet (19:14:20):session got: F73F2838299E3E9088ECE0B56C5D798C
session got: F73F2838299E3E9088ECE0B56C5D798C
localIP0:
current_login is NULL
....
09.09.2015 19:14:20 I: PP_Servlet (19:14:20):session got: F73F2838299E3E9088ECE0B56C5D798C
session got: F73F2838299E3E9088ECE0B56C5D798C
localIP0:
current_login is NULL
Нормальным дебаггером Эклипса пользоваться нельзя, поэтому приходится каждый раз долго деплоить, но я все же выясню, что это за 4 вызова сервлета для одного окна.
Хотя главная фигня мне не нравится: получается, что не только апплет, но и сервлет нельзя поймать, он каждый раз новый что ли?
Хорошо что вы нашли логи, в которые выводится "ndServlet.doPost, SessionID(access key) set: " + session.getId()".
Посмотрите - какой ID выдается в логах при каждом приходящем запросе?
Для дебага выдайте еще
showInfo("ndServlet.doPost, Session Attributes: "+java.util.Collections.list(session.getAttributeNames()));
Хотя главная фигня мне не нравится: получается, что не только апплет, но и сервлет нельзя поймать, он каждый раз новый что ли?
Теоретически такое возможно. Конфигурация вашего серверного контекста ICM6 тоже доставляет. Если к сервлету лезут действительно через него...
Кстати, server.xml, который вы постили тоже как-то кусками послался. Может все-таки xml файл приложится к сообщению?
Проверить можно - хэш-код сервлета в логи выдайте в doPost()
showInfo("ndServlet.doPost hashCode(): "+ hashCode())
и в init()
showInfo("ndServlet.init hashCode(): "+ hashCode())
Увидите сколько раз он инициализировался и какие объекты класса ndServlet обрабатывают запросы.
Посмотрите, может на вашем томкате менеджер поднят, можно посмотреть что же на нем сконфигурировано.
см. http://tomcat.apache.org/tomcat-7.0-doc/manager-howto.html
Еще мыслЯ. В doPost() сделайте
showInfo("ndServlet.doPost request: "+request.hashCode()+" and stacktrace: "+(new Exception()).toString());
Я хочу в логах увидеть stacktrace вызова. Чтобы понять кто и откуда эти 4 раза ваш doPost() вызывает, действительно ли вам 4 разных запроса приходят, или кто-то ваш код 4 раза с одним и ем же запросом вызывает.
Я ведь ставлю значение аттрибута current_id в сессии, сессия сохраняется, а аттрибут нет? Почему?
session у вас это HttpSession, полученное в doPost(HttpRequest request, HttpResponse response) из request.getSession(), верно?
Да.
Посмотрите - какой ID выдается в логах при каждом приходящем запросе?
Каждый раз выдается 596099E13516A03E708161FEE9B16F99.
Посмотрите, может на вашем томкате менеджер поднят, можно посмотреть что же на нем сконфигурировано.
см. http://tomcat.apache.org/tomcat-7.0-doc/manager-howto.html
Я работаю не с локальным Томкатом, а с тем, что запущен на Юниксе. А где там можно посмотреть? И что именно нужно смотреть?
Пробую приложить server.xml...
------
Это - как оно сделано - надо смотреть в твоей реализации.
сессия сохраняется, а аттрибут нет?
------
Вероятно что-то опускаешь. Например, не сохраняешь копию сессии на аппсервере
и новый инстансе сервлета получает от аппсервера копию когда-то сохраненной сессии.


Тебе уже не раз говорилось - это не С/СРР - надо понимать не только что делает код,
но и как работает вся схема. Без этого можно месить код до бесконечности.
Для дебага выдайте еще
showInfo("ndServlet.doPost, Session Attributes: "+java.util.Collections.list(session.getAttributeNames()));
ndServlet.doPost, Session Attributes: [bindings.listener, CURRENT_LOGIN, LAST_ACTION_TIME, javax.security.auth.subject]
showInfo("ndServlet.doPost hashCode(): "+ hashCode())
10.09.2015 11:40:57 I: PP_Servlet (11:40:57):ndServlet.doPost, getAttribute(KEY_BINDING_LISTENER) <> this
10.09.2015 11:40:57 I: PP_Servlet (11:40:57):ndServlet.doPost hashCode(): 625485128
и в init()
showInfo("ndServlet.init hashCode(): "+ hashCode())
10.09.2015 11:16:41 I: PP_Servlet (11:16:41):ndServlet.init hashCode(): 1505384890
10.09.2015 11:16:41 I: PP_Servlet (11:16:41):ndServlet.init: init called ...
10.09.2015 11:26:44 I: PP_Servlet (11:26:44):ndServlet.init: init called ...
10.09.2015 11:26:44 I: PP_Servlet (11:26:44):ndServlet.init hashCode(): 625485128
10.09.2015 11:26:44 I: PP_Servlet (11:26:44):ndServlet.init: init called ...
showInfo("ndServlet.doPost request: "+request.hashCode()+" and stacktrace: "+(new Exception()).toString());
10.09.2015 11:46:27 I: PP_Servlet (11:46:27):ndServlet.doPost request: 1957459116 and stacktrace: java.lang.Exception
10.09.2015 11:46:27 I: PP_Servlet (11:46:27):ndServlet.doPost request: 251137784 and stacktrace: java.lang.Exception
10.09.2015 11:46:57 I: PP_Servlet (11:46:57):ndServlet.doPost request: 1957459116 and stacktrace: java.lang.Exception
10.09.2015 11:46:57 I: PP_Servlet (11:46:57):ndServlet.doPost request: 251137784 and stacktrace: java.lang.Exception
Если до завтра не сделаю, то таск, видимо, снимается и мне запишут жирный минус..

сессия сохраняется, а аттрибут нет?
------
Вероятно что-то опускаешь. Например, не сохраняешь копию сессии на аппсервере
и новый инстансе сервлета получает от аппсервера копию когда-то сохраненной сессии.
К сессии идет обращение через сервлет 4 раза!
И каждый раз ставится аттрибут current_session, и каждый раз он теряется!
Это что, 4 копии одной сессии?

Быть такого не может!..
Каждый раз выдается 596099E13516A03E708161FEE9B16F99.
Ерунда какая-то. Если сессия каждый раз та же самая, то почему не сохраняется аттрибут. А если сессия разная, то почему всегда ID одинаковый.
server.xml нормально передался. Посмотрите в томкатовском каталоге conf, есть ли там (или в его подкаталогах) файлы context<xxx>.xml в которых ваш ndSerlvet упоминается. Где-то же кто-то делает нестандартные вещи с сессией.
А что у вас в каталоге /home/icm6/dcc/web/lib? Может там все-таки номальные дескрипторы есть... Поищите в этои каталоге файлы web.xml. Если найдете такой, в котором ndServlet упоминается (или другие сервлеты из вашего приложения) - шлите.
Даже выкинуть все нафиг и настроить нормально веб-приложение с описанием деплоймента сервлета не посоветуешь, 100% работа сервера завязана на том, что у сессии один и тот же ID...
Я работаю не с локальным Томкатом, а с тем, что запущен на Юниксе. А где там можно посмотреть? И что именно нужно смотреть?
По ссылку написано что такое менеджер и как его открывать. А посмотреть на нем можно запущенные на сервере приложения.
ndServlet.doPost, Session Attributes: [bindings.listener, CURRENT_LOGIN, LAST_ACTION_TIME, javax.security.auth.subject]
Это в самом начале doPost-а выдается? Или после того как вы уже с setAttribute CURRENT_LOGIN и LAST_ACTION_TIME установили?
10.09.2015 11:26:44 I: PP_Servlet (11:26:44):ndServlet.init: init called ...
10.09.2015 11:26:44 I: PP_Servlet (11:26:44):ndServlet.init hashCode(): 625485128
10.09.2015 11:26:44 I: PP_Servlet (11:26:44):ndServlet.init: init called ...
Это как вообще?
1 раз init вызвался, напечатался только " init called ..." а следующий раз пишутся оба, и "init called ..." и "init hashCode(): 625485128"? Вы что, выдачу "init hashCode(): 625485128" в какой-то if засунули что ли?
Ну а вообще - поздравляю. Многократная инициализация двух образцов (а то и больше) сервлета. И это при каждом запросе или все же один раз?
Давайте посмотрим из каких контекстов такая красота идет.
в начале init-а сразу после super.init(config) :
showInfo(getClass.getName()+"@"+hashCode()+".init() called. Servlet name: "+config.getServletName()+" Context Name: "+config.getServletContext().getServletContextName());
showInfo("Servlet configuration parameters: "+Collections.list(config.getInitParameterNames()));
Остальные два вызова showInfo (с " init called ..." и "init hashCode(): ...") сотрите чтобы не засоряло лог.
Дальше.
10.09.2015 11:46:27 I: PP_Servlet (11:46:27):ndServlet.doPost request: 1957459116 and stacktrace: java.lang.Exception
10.09.2015 11:46:27 I: PP_Servlet (11:46:27):ndServlet.doPost request: 251137784 and stacktrace: java.lang.Exception
10.09.2015 11:46:57 I: PP_Servlet (11:46:57):ndServlet.doPost request: 1957459116 and stacktrace: java.lang.Exception
10.09.2015 11:46:57 I: PP_Servlet (11:46:57):ndServlet.doPost request: 251137784 and stacktrace: java.lang.Exception
Два разных запроса, ок. А через 30 секунд еще раз эта же пара, фантастика.
Поправьте код для логов, чтобы все же стэктрейс выдался:
Exception tmp = new Exception();
StringWriter writer = new StringWriter();
tmp.printStackTrace(new PrintWriter(writer));
showInfo("ndServlet@"+hashCode()+".doPost request@"+request.hashCode()+" URL: "+request.getRequestURL()+" Session@"+session.hashCode()+" with ID "+session.getId()+" from cookie? "
+ request.isRequestedSessionIdFromCookie()+" or from URL? "+request.isRequestedSessionIdFromURL()
+ " Stacktrace: "+writer.toString());
Если до завтра не сделаю, то таск, видимо, снимается и мне запишут жирный минус..
Когда начальство дурное это плохо, да.
Ерунда какая-то. Если сессия каждый раз та же самая, то почему не сохраняется аттрибут. А если сессия разная, то почему всегда ID одинаковый.
Oh yes, that is the question, как говорилось у Вильяма нашего Шыкспира...
server.xml нормально передался. Посмотрите в томкатовском каталоге conf, есть ли там (или в его подкаталогах) файлы context<xxx>.xml в которых ваш ndSerlvet упоминается. Где-то же кто-то делает нестандартные вещи с сессией.
Есть файл context.xml, но он полупустой (теги раскрываю, иначе они тут не показываются)
-> cat context.xml
The contents of this file will be loaded for each web application -->
xml version="1.0" encoding="UTF-8"?>
Context allowLinking="true">
-- Default set of monitored resources -->
<WatchedResource>WEB-INF/web.xml</WatchedResource>
Uncomment this to disable session persistence across Tomcat restarts -->
Manager pathname="" />
/Context>
А что у вас в каталоге /home/icm6/dcc/web/lib? Может там все-таки номальные дескрипторы есть... Поищите в этои каталоге файлы web.xml. Если найдете такой, в котором ndServlet упоминается (или другие сервлеты из вашего приложения) - шлите.
web.xml там нет, есть три файла, которые я туда "деплойю", но они, есесна, бинарные:
-rw-r--r-- 1 icm6 icmdev 85443 Sep 10 11:26 dcc_guitext.properties
-rwxr-x--- 1 icm6 icmdev 1752297 Sep 10 11:26 dcc_domain.jar
-rw-r--r-- 1 icm6 icmdev 1774816 Sep 10 11:26 pp_domain.jar
В одном из них, очевидно, что-то содержится на эту темку в бинарной форме, но grep не показывает:
-> grep ndServlet *
grep: can't open ICM-9.3-Benutzerhandbuch.pdf
pp_domain.jar:
pp_domain.jar:
jar-ы это обычные zip-ы. В них могут быть каталог WEB-INF с web.xml внутри.
(я немного расширил в предыдущем сообщении выдачу в лог - будете вставлять, посмотрите что последнее вставляете).
-----
Ну не может так не может.


Правда это наиболее распространенная и труднопонимаемая (для начинающих) ошибка.

И Я надеюсь, что это все же она, а не проблема с правами для процесса в котором выполняется
сервлет.
Это что, 4 копии одной сессии?
-----
А чем тебя смущает количество копий?
Если смущает - обработай корректно следующее:
- приходит запрос и запускается сервлет
- сервлет что-то считает
- приходит еще один запрос и запускается еще одна копия сервлета
- сервлет что-то считает
- приходит еще один запрос и запускается еще одна копия сервлета
и еще так же 100500 раз...
Что ты будешь делать с сессиями, при условии, что место хранения сессионной информации
- какая-то база данных размещенная где-то на хосте, отличном от апп.сервера?
Или ты полагаешь, что для второго и последующих сервлетов используется другой алгоритм
запуска?

Это в самом начале doPost-а выдается? Или после того как вы уже с setAttribute CURRENT_LOGIN и LAST_ACTION_TIME установили?
Это выдается до того, как я setAttribute CURRENT_LOGIN и LAST_ACTION_TIME установил, но не в начале, а после
// now handle special case: multi block transfer
// (in case of own support for communication)
if (!(objTransfer.getData- -() instanceof ndCommunication- -) ||
!c_fSpecialCommunicationSupport)
ибо сессия определяется уже после этого if:
// set binding listener for session if it's not already done...
HttpSession session = request.getSession(true);
Впрочем, я могу перенести этот кусок и в начало метода doPost, если надо.
Это как вообще?
1 раз init вызвался, напечатался только " init called ..." а следующий раз пишутся оба, и "init called ..." и "init hashCode(): 625485128"? Вы что, выдачу "init hashCode(): 625485128" в какой-то if засунули что ли?
Нет, не в if. Просто дебаг "init called" у меня пишется сначала не в самом сервлете, а в классе ndReportServlet, а потом уже в init самого класса ndServlet:
showInfo("ndServlet.init hashCode(): "+ hashCode());
String hostname;
String maxBlockSize;
int tracelevel;
//In the Moment, we set no Security! It remains to check, if you can do it with policy-files
//System.setSecurityManager(new NoSecurityManager());
// Trace on/off?
if (config.getInitParameter("Trace") != null)
{
tracelevel = Integer.parseInt(config.getInitParameter("Trace"));
if ((tracelevel > Trace.TRACE_OFF) &&
(tracelevel <= Trace.FUNCTION_TRACE))
Trace.setTraceLevel(tracelevel);
}
showInfo("ndServlet.init: init called ...");
Так что многократной инициализации все же нет, init вызывается 1 раз.
в начале init-а сразу после super.init(config) :
showInfo(getClass.getName()+"@"+hashCode()+".init() called. Servlet name: "+config.getServletName()+" Context Name: "+config.getServletContext().getServletContextName());
showInfo("Servlet configuration parameters: "+Collections.list(config.getInitParameterNames()));
Первую строчку вставить не получается, getClass не находится. Вторую вставил, инклюдировав Collections.
+request.getRequestURL()
Очень странно, +request.getRequestURL() не находится, но есть +request.getRequestURI()
10.09.2015 13:44:58 I: PP_Servlet (13:44:58):Servlet configuration parameters: [HostName, Trace]
showInfo("ndServlet@"+hashCode()+".doPost request@"+request.hashCode()+" URL: "+request.getRequestURL()+" Session@"+session.hashCode()+" with ID "+session.getId()+" from cookie? "
+ request.isRequestedSessionIdFromCookie()+" or from URL? "+request.isRequestedSessionIdFromURL()
+ " Stacktrace: "+writer.toString());
-> grep "ndServlet@" tomcat.log
10.09.2015 13:44:58 I: PP_Servlet (13:44:58):ndServlet@41943680.doPost request@1957459116 URL: /ICM6/servlet/de.novadata.pp.servlet.ndServlet sessionID from cookie? true or from URL? false Stacktrace: java.lang.Exception
10.09.2015 13:44:58 I: PP_Servlet (13:44:58):ndServlet@41943680.doPost request@251137784 URL: /ICM6/servlet/de.novadata.pp.servlet.ndServlet sessionID from cookie? true or from URL? false Stacktrace: java.lang.Exception
10.09.2015 13:45:28 I: PP_Servlet (13:45:28):ndServlet@41943680.doPost request@1957459116 URL: /ICM6/servlet/de.novadata.pp.servlet.ndServlet sessionID from cookie? true or from URL? false Stacktrace: java.lang.Exception
Вместо того, чтобы троллить подзаборными словами, запрещенными свыше, выдай уже что-нить конструктивное.
Например, откуда взять getClass для дибага.
-----
Почему не сохряется?
Вполне себе сохраняется - его можно извлечь... из текущей копии сессии. т.е. до окончания
работы сервлета.
А что при повторном запуске его нет - Я ему уже написал про наиболее вероятную версию
ошибки. Только он пИсатель - читать еще не научился...

Это выдается до того, как я setAttribute CURRENT_LOGIN и LAST_ACTION_TIME установил, но не в начале, а после
А почему же вы сначала пишите что
Я ведь ставлю значение аттрибута current_id в сессии, сессия сохраняется, а аттрибут нет? Почему?
а теперь что в сессии есть аттрибуты CURRENT_LOGIN и LAST_ACTION_TIME до того, как вы их устанавливаете в с помощью setAttribute()?
Просто дебаг "init called" у меня пишется сначала не в самом сервлете, а в классе ndReportServlet,
Мнэ. Так может поправить логи в ndReportServlet-е, чтобы он писал "ndReportServlet.init:" а не "ndServlet.init:" в логи?
Первую строчку вставить не получается, getClass не находится. Вторую вставил, инклюдировав Collections.
Вы до прошлой пятницы с явой вообще не сталкивались? getClass() это метод Object-а. Просто добавьте скобки.
Впрочем, я могу перенести этот кусок и в начало метода doPost, если надо.
Давайте так, в начало метода doPost, самыми первыми строчками вы пишите
HttpSession session = request.getSession();
Exception tmp = new Exception();
StringWriter writer = new StringWriter();
tmp.printStackTrace(new PrintWriter(writer));
showInfo("ndServlet@"+hashCode()+".doPost request@"+request.hashCode()+" URL: "+request.getRequestURL()+" Session@"+session.hashCode()+" with ID "+session.getId()+" from cookie? "
+ request.isRequestedSessionIdFromCookie()+" or from URL? "+request.isRequestedSessionIdFromURL()
+ " Stacktrace: "+writer.toString());
Enumeration<?> attributes = session.getAttributeNames();
showInfo("Session Attributes: "+Collections.list(attributes));
while(attributes.hasMoreElements()){
String name = attributes.nextElement().toString();
String value = session.getAttribute(name).toString();
showInfo(name +" = "+value);
}
-----
Конструктивное тебе УЖЕ дано - ты его просто не воспринимаешь...
Ну попробую так.
Представь себе файл. Ты его один раз прописал и каждый раз читаешь при запуске сервлета... ну скажем в строковую переменную.
Потом ты работаешь с этой строковой переменной - добавил, вырезал, заменил.
Что у тебя будет при следующем запуске сервлета?
Вот это и есть модель работы с сессией - аппсервер как ФСО.
откуда взять getClass для дибага.
-----
Ну Я бы подумал об том откуда в статическом методе возьмется <this>.
Почему не сохряется?
Вполне себе сохраняется - его можно извлечь... из текущей копии сессии. т.е. до окончания
работы сервлета.
Сессия томката не привязана к сервлету. Она привязана к контексту. Несколько сервлетов запущенных в одном контексте могут работать с одной сессией. Даже если сервлет "окончил работу" сессия не исчезает.
Вообще сервлет не должен перезапускаться. Он должен инициализироваться один раз. Но даже если бы он перезапускался он получал бы все ту же сессию.
Вот это и есть модель работы с сессией - аппсервер как ФСО.
Чушь. Сохранять сессию имеет смысл только для обмена ею с другими приложениями / вебконтейнерами. Например, если у нас на нескольких серверах за Loadbalancer-ом поднято то же приложение, и надо чтобы оно на всех серверах работало в одной сессии. В одиночном томкате сессия простой объект класса HttpSession.
-----
Исчезает та копия с которой он работал. Остается - та, которая была загружена на аппсервер. В данном случае - ТомКат.
Вообще сервлет не должен перезапускаться. Он должен инициализироваться один раз.
-----
Инстанцируется (или клонируется) при получении запроса. Основание - <HTTP>-протокол есть <state less> протокол
- каждый запрос обрабатывается независимо от предыдущих/других/следующих.
В одиночном томкате сессия простой объект класса HttpSession.
------
Ну начнем с того, что:
- а. у аппсервера не одна <HttpSession>, а набор/коллекция...
- б. коллекция - именно у аппсервера, а не у отдельная сессия у сервлета...
- в. инстансе сервлета работает с копией/клоном сессии хранимой аппсервером.
Просто протестируй - там элементарно все проверяется.
Сохранять сессию имеет смысл только для обмена ею с другими приложениями / вебконтейнерами.
------
Тяжело.
Остается только спросить - что будет при многократных, до окончания выполнения, запросах (и запусках)
сервлета и хранении в сессиях каких-то промежуточных данных? Ну скажем запрет на повторный вход в
контекстно-критическую секцию кода... при условии, что она критична только для данной копии сервлета.
Как будешь разгребать? Ответ - никак - у тебя нет доступа к другому инстансу. Почему этой проблемы нет?
Да потому что копия сессии у каждого своя. А оригинал - у аппсервера.
Исчезает та копия с которой он работал. Остается - та, которая была загружена на аппсервер. В данном случае - ТомКат.
Чушь. Это один и тот же явовский объект. Вебконтейнер теоретически может создавать новый объект (клон) HttpSession с теми же данными для нового запроса, но так как параллельные запросы для одной и той же сесстии достаточно редкая вещь то вряд ли хоть кто-то такое делает. Я не знаю ни одного сервлет-контейнера создающего копии сессии для каждого запроса.
Инстанцируется (или клонируется) при получении запроса.
Нет. RTFM. Сервлет - синглтон (если ручками не поломать это поведение). Один и тот же объект используется разными потоками.
Основание - <HTTP>-протокол есть <state less> протокол - каждый запрос обрабатывается независимо от предыдущих/других/следующих.
Логика! Убил. А может тогда весь сервер перегружать для каждого запроса? Ведь "<HTTP>-протокол есть <state less> протокол".
А зачем вообще придумали сессии не подскажете?
- а. у аппсервера не одна <HttpSession>, а набор/коллекция...
- б. коллекция - именно у аппсервера, а не у отдельная сессия у сервлета...
И? А небо голубое, а травка зеленая.
- в. инстансе сервлета работает с копией/клоном сессии хранимой аппсервером.
Кто вам такое рассказал? Multiple servlets executing request threads may have active access to a single session object at the same time. The Developer has the responsibility for synchronizing access to session resources as appropriate.
Почитайте http://www.ibm.com/developerworks/library/j-jtp09238/index.html что ли.
Тяжело.
И не говорите. Ведь зарекался с вами общаться, потому как постоянно с гигантским апломбом несете чушь про то, в чем вообще не разбираетесь...
Остается только спросить - что будет при многократных, до окончания выполнения, запросах (и запусках)
сервлета и хранении в сессиях каких-то промежуточных данных?
В нескольких потоках (да-да каждый запрос контейнер обрабатывает в отдельный свободном потоке) будет выполнятся один и тот же код у одного и того же объекта (конечно, внутри потока создается своя "копия" объекта, которая синхронизируется или принудительно, или когда свободное время будет с "оригиналом". Как реализованы потоки на яве вам рассказывать не надо?)
Код сервлета должен быть thread-safe. "Промежуточные данные" следует хранить в сессии не забывая что одноверменно могут работать много потоков. Что опять же в обной и той же сессии происзодит не так часто. При AJAX-овский запросах бывает, да. Или синхронизируем доступ, или привязываем к потоку.
Ну скажем запрет на повторный вход в контекстно-критическую секцию кода...
Вы про синхронизацию слышали?
Почему этой проблемы нет?
Потому что у тех, кто умеет программировать многопоточные приложения, этой проблемы просто нет.
А почему же вы сначала пишите что
В ответ на:Я ведь ставлю значение аттрибута current_id в сессии, сессия сохраняется, а аттрибут нет? Почему?
а теперь что в сессии есть аттрибуты CURRENT_LOGIN и LAST_ACTION_TIME до того, как вы их устанавливаете в с помощью setAttribute()?
ОК, я переставил строчку
showInfo("ndServlet.doPost, Session Attributes: "+java.util.Collections.list(session.getAttributeNames()));
в конец методы. Была моя ошибка, сорри.
Мнэ. Так может поправить логи в ndReportServlet-е, чтобы он писал "ndReportServlet.init:" а не "ndServlet.init:" в логи?
Я поправил. Но это была не моя ошибка, оба этих дибаг-аута стояли еще до меня.
getClass() это метод - --а. Просто добавьте скобки.
Да, ступил

P.S. Вместо config.getServletContext().getContextName() написал config.getServletContext().getServerInfo().
У него нет метода getContextName().
showInfo(getClass().getName()+"@"+hashCode()+".init() called. Servlet name: "+config.getServletName()+" Context Name: "+(config.getServletContext().getServerInfo()));
-> grep "init() called. Servlet name:" tomcat.log
10.09.2015 15:55:39 I: PP_Servlet (15:55:39):de.novadata.pp.servlet.ndServlet@725887812.init() called. Servlet name: de.novadata.pp.servlet.ndServlet Context Name: Apache Tomcat/5.5.31
10.09.2015 15:56:10 I: PP_Servlet (15:56:10):de.novadata.pp.servlet.ndServlet@1155286236.init() called. Servlet name: de.novadata.pp.servlet.ndServlet Context Name: Apache Tomcat/5.5.31
showInfo("Servlet configuration parameters: "+Collections.list(config.getInitParameterNames()));
-> grep "Servlet configuration parameters" tomcat.log
10.09.2015 13:45:54 I: PP_Servlet (13:45:54):Servlet configuration parameters: [HostName, Trace]
10.09.2015 15:55:39 I: PP_Servlet (15:55:39):Servlet configuration parameters: [HostName, Trace]
10.09.2015 15:56:10 I: PP_Servlet (15:56:10):Servlet configuration parameters: [HostName, Trace]
Метода doPost():
showInfo("ndServlet@"+hashCode()+".doPost request@"+request.hashCode()+" URL: "+request.getRequestURI()+" Session@"+session.hashCode()+" with ID "+session.getId()+" from cookie? "
+ request.isRequestedSessionIdFromCookie()+" or from URL? "+request.isRequestedSessionIdFromURL()
+ " Stacktrace: "+writer.toString());
10.09.2015 16:07:23 I: PP_Servlet (16:07:23):ndServlet@1155286236.doPost request@850145964 URL: /ICM6/servlet/de.novadata.pp.servlet.ndServlet Session@973355524 with ID 71AFAE004EC7552C250523BCBDD847F8 from cookie? true or from URL? false Stacktrace: java.lang.Exception
10.09.2015 16:07:23 I: PP_Servlet (16:07:23):ndServlet@1155286236.doPost request@850145964 URL: /ICM6/servlet/de.novadata.pp.servlet.ndServlet sessionID from cookie? true or from URL? false Stacktrace:
10.09.2015 16:07:23 I: PP_Servlet (16:07:23):ndServlet@1155286236.doPost request@2042657216 URL: /ICM6/servlet/de.novadata.pp.servlet.ndServlet Session@973355524 with ID 71AFAE004EC7552C250523BCBDD847F8 from cookie? true or from URL? false Stacktrace: java.lang.Exception
10.09.2015 16:07:23 I: PP_Servlet (16:07:23):ndServlet@1155286236.doPost request@2042657216 URL: /ICM6/servlet/de.novadata.pp.servlet.ndServlet sessionID from cookie? true or from URL? false Stacktrace:
10.09.2015 16:07:53 I: PP_Servlet (16:07:53):ndServlet@1155286236.doPost request@126617484 URL: /ICM6/servlet/de.novadata.pp.servlet.ndServlet Session@973355524 with ID 71AFAE004EC7552C250523BCBDD847F8 from cookie? true or from URL? false Stacktrace: java.lang.Exception
10.09.2015 16:07:53 I: PP_Servlet (16:07:53):ndServlet@1155286236.doPost request@126617484 URL: /ICM6/servlet/de.novadata.pp.servlet.ndServlet sessionID from cookie? true or from URL? false Stacktrace:
10.09.2015 16:07:53 I: PP_Servlet (16:07:53):ndServlet@1155286236.doPost request@126486410 URL: /ICM6/servlet/de.novadata.pp.servlet.ndServlet Session@973355524 with ID 71AFAE004EC7552C250523BCBDD847F8 from cookie? true or from URL? false Stacktrace: java.lang.Exception
(есчо много, много раз...)
showInfo("Session Attributes: "+Collections.list(attributes));
10.09.2015 16:11:53 I: PP_Servlet (16:11:53):Session Attributes: [bindings.listener, CURRENT_LOGIN, LAST_ACTION_TIME, javax.security.auth.subject]
10.09.2015 16:12:23 I: PP_Servlet (16:12:23):Session Attributes: [bindings.listener, CURRENT_LOGIN, LAST_ACTION_TIME, javax.security.auth.subject]
10.09.2015 16:12:23 I: PP_Servlet (16:12:23):Session Attributes: [bindings.listener, CURRENT_LOGIN, LAST_ACTION_TIME, javax.security.auth.subject]
10.09.2015 16:12:53 I: PP_Servlet (16:12:53):Session Attributes: [bindings.listener, CURRENT_LOGIN, LAST_ACTION_TIME, javax.security.auth.subject]
10.09.2015 16:12:53 I: PP_Servlet (16:12:53):Session Attributes: [bindings.listener, CURRENT_LOGIN, LAST_ACTION_TIME, javax.security.auth.subject]
(есчо много, много раз...)
while(attributes.hasMoreElements()){
String name = attributes.nextElement().toString();
String value = session.getAttribute(name).toString();
showInfo(name +" = "+value);
10.09.2015 13:45:54 I: generated test access key = 0.051317529712655574
10.09.2015 15:55:39 I: generated test access key = 0.9605675906009544
10.09.2015 15:56:10 I: generated test access key = 0.6988406994261954
-----
Тестируй. Я, в свое время, бодался с этой проблемой под ВебСферой.
А лучше - почитай там где более просто описано - например у тех же мелкомягких, в популярном изложении.
Это один и тот же явовский объект.
-----
По поводу одного и того же явовского обьекта - повеселил... т.е. сидит себе персистантный сервлет на аппсервере, ждет когда придет запрос, хранит инстансе своей сессии... и тут приходят ему ДВА запроса... да еще и из РАЗНЫХ мест... Ха-ха-ха...
Если не понял юмора - из разных мест - работать он должен с разными <HttpSession>... и - одновремненно...

Тестируй данный момент. Там не сложно - поместил - прочитал - все есть - второй запрос - пусто, но в первом - все еще есть...
Сервлет - синглтон
-----
Ага... Код этого синглтона приведи, плс... а то как-то закрытого конструктора и статического
инстанса не наблюдается... А вот конструктор, если его написать, дергается регулярно...
Это же не <RMI>, а <HTTP>...
Кто вам такое рассказал?
-----
Практика. Старая добрая практика.
Вы про синхронизацию слышали?
-----
Хи-хи... Что с чем и через что? Только не говори, что код сервлета зависит от того на чем его
запускают - на отдельном сервисе или на ферме...
Потому что у тех, кто умеет программировать многопоточные приложения, этой проблемы просто нет.
-----
У тебя много знакомых пишущих многопоточные приложения и зачем-то еще подрабатывающих веб-разработкой?
Веб, по определению, пишут, в основном, полные дилетанты... А вот проблемы - действительно нет.
Как реализованы потоки на яве вам рассказывать не надо?)
-----
Можно, но бесполезно - у меня к ним интерес оч.маленький - не профилное...
Ну попробую так.
Представь себе файл. Ты его один раз прописал и каждый раз читаешь при запуске сервлета... ну скажем в строковую переменную.
Потом ты работаешь с этой строковой переменной - добавил, вырезал, заменил.
Что у тебя будет при следующем запуске сервлета?
Тут уже много раз было сказано, что писать в файл - это детский сад.
Вот в БД еще куда ни шло..

Уж не говоря о том, что у меня на ферме все локальные дисководы закрыты от записи, а связь с личной частью центрального диска часто теряется

Меня щас интересует другое, как ты понимаешь, почему аттрибут в сессии не сохраняется.
К тому же в идее записывать залогиненность куда-нибудь, где не сопрут, не хватает одного важного элемента: что делать, если юзер закрыл окно щелчком, сессия осталась, в таблице он числится залогиненным для этой сессии? Тогда ни одно окно больше не откроется, пока сессия не умрет от старости и болезней или кто-нибудь не перезапустит Томкат.
С куками работать не получается, как ты видишь, запрещены они апплету.
в сессии не сохраняется.
-----
Хи-хи... Аккурат взаимоисключающие утверждения.
Модель и была дана именно для того, чтобы ты понял где именно у тебя затык.
Но думать самостоятельно - придется.
не хватает одного важного элемента
------
Это уже как ты у себя все организуешь.
К тому же

Осталось только осознать и проимплементить...

Над записью в БД я и так работаю, для этого мне твои каменты не нужны
Вот если б подсказал, как без этого, шоб атрибут сохранялся, но тут ты, видно, не силен

Нащщет многих копий одной сессии, у которых у всех один и тот же идентификатор, - это, мне чуется, новое слово в программировании.
Зачем тогда вообще эти атрибуты придумали, если каждый раз другая копия и атрибуты в них никогда не синхронизируются?
Тестируй. Я, в свое время, бодался с этой проблемой под ВебСферой.
У меня "в свое время" ни под сферой ни под томкатом таких проблем не было. При том что у нас был параллельный доступ в одному сервлету в одной и той же сессии (несколько одновременный AJAXовских запросов).
Что дальше?
А лучше - почитай там где более просто описано - например у тех же мелкомягких, в популярном изложении.
А зачем мне читать у мелкомягких? С каких пор они что-то делают для явы, да еще и не соответсвующее сановской (теперь оракловской) спецификации?
Под вебсферой можно, например, включить сериализацию запросов. По дефолту запросы с доступом к сессии обрабатываются параллельно. Читайте, если можете: www-01.ibm.com/support/knowledgecenter/SSAW57_8.5.5/com.ibm.websphere.nd....
По поводу одного и того же явовского обьекта - повеселил... т.е. сидит себе персистантный сервлет на аппсервере, ждет когда придет запрос, хранит инстансе своей сессии... и тут приходят ему ДВА запроса... да еще и из РАЗНЫХ мест... Ха-ха-ха...
Если не понял юмора - из разных мест - работать он должен с разными <HttpSession>... и - одновремненно...
"Дядя Петя, ты дурак?" (с) Сервлет не хранит референс на сессию (если не полный илиот его писал). Объект класса HttpSession управляется контейнером. Что такое "персистантный сервлет" в вашем воспаленном мозгу я не знаю. Но в жизни все происходит так:
1. Запускается контейнер.
2. Все сервлеты, сконфигурированные как "инициализируйся при запуске" инициализируются, т.е. контейнер создает ОДИН объект и вызывает у него init(...)
3. Если сервлет не инициализирован а к нему приходит запрос, то при первом запросе контейнер создает ОДИН объект и вызывает у него init(...)
4. При каждом запросе, который обрабатывается сервлетом в своем "worker" Thread-е контейнер смотрит сконфигурирован ли у него сервлет для URL запроса. Если да, то контейнер находит наш ЕДИНСТВЕННЫЙ объект для нужного контекста и запускает в этом потоке метод service(...) который определяет что за запрос пришел и запускает подходящий doXXX(...) метод.
Фсё. Одновременно в 100 разных потоках может работать код из метода doGet() одного объекта. В 50 потоках с сессией А а в остальных 50 с сессией Б. В чем проблема-то?
Да, зная вас, оговорюсь - это стандартное поведение. Можно и на томкате и на (насколько я помню) вебсфере заставить для каждого запроса создавать новый объект сервлета и убивать его после обработки запроса. Что неплохо так поднимает нагрузку. Делается в основном только на тестовых серверах, чтобы обеспечить возможность быстро и ненапряжно перегрузить сервлет. Контейнер также может и просто так прибить сервлет (чтобы память освободит, например) вызвав destory() и к этому тоже надо быть готовым (но можно и запретить).
Можно заставить контейнер создавать несколько копий сервлета. Но стандартное поведение - ОДНА копия. Специально для вас - из спецификаций сервлета. Английский вы вроде бы понимаете...
For a servlet not hosted in a distributed environment (the default), the servlet container must use only one instance per servlet declaration. However, for a servlet implementing the SingleThreadModel interface, the servlet container may instantiate multiple instances to handle a heavy request load and serialize requests to a particular instance.
Тестируй данный момент. Там не сложно - поместил - прочитал - все есть - второй запрос - пусто, но в первом - все еще есть...
Дядя, я прям вот щас в одном веб-приложении ковыряюсь. Хоть сервлет и не мой. Вы их "когда-то 100500 лет назад вроде бы что-то делал, но забыл", а я последний крупный проект с сервлетами в 2010 делал.
Не врите о том, чего вы не знаете, хорошо?
Ага... Код этого синглтона приведи, плс... а то как-то закрытого конструктора и статического инстанса не наблюдается...
Уй блин. А если у меня другой класс А хранит в хэшмэпе ссылку на объект класса Б, и доступ к нему только через методы класса А, и он гарантирует что в любой момент у меня только один инстанс класса Б есть, то что, я не могу назвать класс Б (в этом контексте) синглтоном?
Практика. Старая добрая практика.
Фиговая у вас практика. Ни со спецификацией не соотносится, ни с чужими практиками.
Хи-хи... Что с чем и через что? Только не говори, что код сервлета зависит от того на чем его запускают - на отдельном сервисе или на ферме...
Понял - не слышали. synchronized(...){} никогда не видели?
И код сервера таки зависит от того как его будут запускать. Я могу вам такое написать что при попытке запустить его одновременно без sticky sessions на нескольких хостах за лоадбалансером сервлет будет очень весело работать. Например, можно лезть в контекст. А он, в отличие от сессии между хостами не копируется. Вот же засада, да?
У тебя много знакомых пишущих многопоточные приложения и зачем-то еще подрабатывающих веб-разработкой?
Ога. Потому что веб-разработка это не только странички на cms-ах клепать.
Можно, но бесполезно - у меня к ним интерес оч.маленький - не профилное...
Не профильное это слишком мягко сказано.
Все замечательно... только не работает...


Последний разок с пропадающем из сессии значением Я таки сталкивался не так давно. Но не с Жабой.
Хотя мог работать и с жабой - методика - та же.

Еще видно что CURRENT_LOGIN, LAST_ACTION_TIME в сессии есть. Или вы не перенсли эту строчку в начало doPost-а?
Почему у вас два раза выдается лог для поста (разный)? Но хэши запросов - разные. Объекты значит разные. Почему строчки отличаются?
10.09.2015 16:07:53 I: PP_Servlet (16:07:53):ndServlet@1155286236.doPost request@126617484 URL: /ICM6/servlet/de.novadata.pp.servlet.ndServlet sessionID from cookie? true or from URL? false Stacktrace:
10.09.2015 16:07:53 I: PP_Servlet (16:07:53):ndServlet@1155286236.doPost request@126486410 URL: /ICM6/servlet/de.novadata.pp.servlet.ndServlet Session@973355524 with ID 71AFAE004EC7552C250523BCBDD847F8 from cookie? true or from URL? false Stacktrace: java.lang.Exception
Почему стэктрейса нет в логах? Вы выдачу стектрейса поправили, как я писал?
Вообще, что у вас сейчас в doPost() и в init() получилось? Скопируйте их в текстовый файл и притожите к сообщению.
Чтобы разобраться с doPost-ом добавьте в начала и в конец сетода строчку в лог, вроде
showInfo(getClass().getName()+"@"+hashCode()+".doPost START Request: "+request.getClass().getName()+"@"+request.hashCode()); // первой строчкой
showInfo(getClass().getName()+"@"+hashCode()+".doPost STOP Request: "+request.getClass().getName()+"@"+request.hashCode()); // последней
Потом прогнав тест - найдите в логах и скопируйте ВСЕ логи между START и STOP с одним и тем же хэшем запроса.

Еще видно что CURRENT_LOGIN, LAST_ACTION_TIME в сессии есть. Или вы не перенсли эту строчку в начало doPost-а?
Перенес, но не стер в предыдущем месте. Поэтому 2 раза.
Еще раз, корректно-
Метода init:
11.09.2015 12:27:41 I: PP_Servlet (12:27:41):de.novadata.pp.servlet.ndServlet@1216497794.init() called. Servlet name: de.novadata.pp.servlet.ndServlet Context Name: Apache Tomcat/5.5.31
11.09.2015 12:27:41 I: PP_Servlet (12:27:41):Servlet configuration parameters: [HostName, Trace]
Как видите, инициализируется сервлет 1 раз.
Метода doPost вызывается несколько раз, его вызовы я записал в файл.
Почему стэктрейса нет в логах? Вы выдачу стектрейса поправили, как я писал?
Поправил:
showInfo("ndServlet@"+hashCode()+".doPost request@"+request.hashCode()+" URL: "+request.getRequestURI()+" Session@"+session.hashCode()+" with ID "+session.getId()+" from cookie? "
+ request.isRequestedSessionIdFromCookie()+" or from URL? "+request.isRequestedSessionIdFromURL()
+ " Stacktrace: "+writer.toString());
Enumeration<?> attributes = session.getAttributeNames();
Я не знаю, почему там java.lang.Exception.
Вообще, что у вас сейчас в doPost() и в init() получилось? Скопируйте их в текстовый файл и притожите к сообщению.
Текстовый файл приложить здесь почему-то невозможно, ни doc, ни txt. Только xml. Но попробую еще раз.
Чтобы разобраться с doPost-ом добавьте в начала и в конец сетода строчку в лог, вроде
Добавил.
Потом прогнав тест - найдите в логах и скопируйте ВСЕ логи между START и STOP с одним и тем же хэшем запроса.
Еще раз, если файл не пройдет:
- с запросом request@557326648 - много раз выдается
11.09.2015 12:29:43 I: PP_Servlet (12:29:43):doPost: ndServlet@1216497794.doPost request@557326648 URL: /ICM6/servlet/de.novadata.pp.servlet.ndServlet Session@1889038488 with ID 464079885C8AEC3968E75C57320389DB from cookie? true or from URL? false Stacktrace: java.lang.Exception
- с запросом request@280105138 много раз выдется
11.09.2015 12:31:43 I: PP_Servlet (12:31:43):doPost: ndServlet@1216497794.doPost request@280105138 URL: /ICM6/servlet/de.novadata.pp.servlet.ndServlet Session@1889038488 with ID 464079885C8AEC3968E75C57320389DB from cookie? true or from URL? false Stacktrace: java.lang.Exception
P.S. Как видите, если просто переименовать текстовый файл в xml, то показывается здесь только одна строчка.
В логи stacktrace может быть не попадает из-за переносов строки... Попробуйте так: замените
writer.toString()
на
java.util.Arrays.toString((new Exception()).getStackTrace())
Совершенно ненормально то, что с одним и тем же request-ом апплет вызывается много раз. Потом перерыв в пол-минуты и опять тот же реквест
12:27:44 ... de.novadata.pp.servlet.ndServlet@1216497794.doPost START Request: org.apache.catalina.connector.RequestFacade@557326648
12:28:13 ... de.novadata.pp.servlet.ndServlet@1216497794.doPost START Request: org.apache.catalina.connector.RequestFacade@557326648
Stacktrace.txt
Просто добавляетй к сообщению, перименовав в .xml Скачать и переименовать файл я в состоянии :)
Нужен новый лог (в нем-то стэктрейс есть?) и актуальный ndServlet.java
Прошу пардону.
А в чем разница?
А устанавливаем мы этот атрибут так:
session.setAttribute("CURRENT_LOGIN", "123");
Чтобы таких ошибок не случалось надо использовать константы.
С логикой пока чота не клеится. Проблема в том, что метод doPost() вызывается по многу раз для одного окна. Если я в нем делаю LogOff, то юзера вышибает уже при одном окне. Мне кажется, что всю эту логику надо перенести в init, но там нет request'a, а без него не вытаскивается сессия.
Могу ли я просто изменить jsessionid, если, к примеру, установлен тот же current_login?
(или то же самое с session.isNew()?)
Я перепробовал за эти 2 дня кучу решений, пользователи согласны даже на старт нового окна, чтобы в нем происходило перелогинивание, но всякий раз чего-то не хватает, в init - сессии, doPost - вызывается слишком часто уже внутри одного окна, и до логина, и после, и там еще вызываются какие-то дополнительные сервлеты, поэтому происходит путаница, в Authentification свои проблемки :(
Так что главная проблема сейчас - логика, не только когда перезапускать сессию или перелогиниваться, но и где.
Подскажите, пожалуйста, как перезапустить сессию в сервлете?
никак. "перезапустить" сессию нельзя. Можно существующую сделать недействительной - invalidate().
Но вам это не надо.
Установкой session.setMaxInactiveInterval(0)?
По явовской документации:
An interval value of zero or less indicates that the session should never timeout.
Но некоторые веб-контейнеры ведут себя как вы ожидали - при 0 тут же рушат сессию. Но как вел себя 5.5-й томкат я уже не помню, судя по вашему опыту - как положено по контракту метода.
doPost - вызывается слишком часто уже внутри одного окна
doPost вызывается каждый раз когда вы обращаетесь к сервету. sendRequest или как оно там.
У вас на каждое действие посылается объект определенного класса. При логине что-то там с AuthenticateUser, емнип.
Значит в doPost-е смотрите что вам прислали. Имя класса у вас и в content-type заголовке устанавливается (опять же если я правильно помню).
Смотрите что за объект к вам прислали. Если это AuthenticateUser значит идет попытка логина.
но и где.
doPost()
showInfo("doPost, getClass: " + getClass().getName()+"@"+hashCode()+".doPost
всегда выдает одно и то же, как попугай:
doPost: de.novadata.pp.servlet.ndServlet@1590451916.doPost.
То же самое и в init():
showInfo(getClass().getName()+"@"+hashCode()+".init() called. Servlet name: "+config.getServletName()+" Context Name: "+(config.getServletContext().getServerInfo()));
PP_Servlet (15:55:39):de.novadata.pp.servlet.ndServlet@725887812.init() called. Servlet name: de.novadata.pp.servlet.ndServlet Context Name: Apache Tomcat/5.5.31
showInfo("Servlet configuration parameters: "+Collections.list(config.getInitParameterNames()));
10.09.2015 13:45:54 I: PP_Servlet (13:45:54):Servlet configuration parameters: [HostName, Trace]
Я не знаю, как тут фильтровать этот базар на предмет того, откуда doPost вызывается, а при каждом обращении делать логаут, как Вы понимаете, невозможно.
sendRequest() существует как метод в классе GeneralServerAdapter_Servlet, но тоже нигде эксплицитно не вызывается.
Вытащить content-type из реквеста тоже не получается, request.getContentType() выдает всегда java-internal/de.novadata.pp.baseобжектс.ServletTransferОбжект
Вот все, что я смог вытащить из реквеста:
15.09.2015 23:38:13 I: PP_Servlet (23:38:13): \\\request.getParameterNames(): java.util.Hashtable$1@8400840 \\\request.getServletPath():
/servlet/de.novadata.pp.servlet.ndServlet \\\request.getMethod(): POST \\\request.getParameter(getServletInfo()): null \\\request.getContextPath(): /ICM6 \\\request.getContentType(): java-internal/de.novadata.pp.baseобжектs.ServletTransferОбжект
// first get the request Object
ObjectInputStream objIn = new ObjectInputStream(request.getInputStream());
ServletTransferObject objTransfer = (ServletTransferObject)objIn.readObject();
objIn.close();
Вы считали ServletTransferObject из запроса. Этот объект вы отправляли на сервлет из апплета. Посмотрите что в этот объект засовывается в апплете когда пользователь логинится и на стороне сервлета сравнивайте содержимое с ожидаемым для аутентификации.
напишите метод public boolean isAuthorizationRequest(ServletTransferObject)
doPost() нигде эксплицитно не вызывается
В вашем коде - нет. Его вызывает веб-контейнер. Томкат.
всегда выдает одно и то же, как попугай: doPost: de.novadata.pp.servlet.ndServlet@1590451916.doPost.
Потому что она выдает имя класса сервлета. С чего бы ему меняться?
Я не знаю, как тут фильтровать этот базар на предмет того, откуда doPost
Не откуда, а с какими данными в HttpRequest-е. Вы уже разобрались как в принципе работает общение клиента с сервлетом?
вчерашний день выпал у меня для тестирования, сегодня я попробовал реализовать Вашу идею.
При логине можно отследить, что идет обращение сервера аутентификации, но это обращение
происходит ровно 20 раз, т.е. 20 раз повторяется строчка типа
17.09.2015 12:41:03 I: PP_Servlet (12:41:03):1: objTransfer: objTransfer.getAdapterClass():
de.novadata.pp.authenticationdomain.AuthenticationServerAdapter_RMI ###objTransfer.getAdapterMethod(): getForcedLogOff
###objTransfer.getArgumentClass()de.novadata.pp.authenticationdomain.AuthenticationData ###objTransfer.toString():
de.novadata.pp.baseОбжектs.ServletTransferОбжект@79487948 ###objTransfer.getClass(): class
de.novadata.pp.baseОбжектs.ServletTransferОбжект ###objResult.getClass(): class java.lang.Boolean ###objResult.toString(): false
Это вся инфа, которую мне удалось вытащить из objTransferОбжекта, objResult
Мне нужно каким-то образом определить первое обращение сервера аутентификации к сервлету.
1. Еще до логина тоже есть одно обращение от сервера аутентификации:
17.09.2015 13:22:22 I: PP_Servlet (13:22:22):1: objTransfer: objTransfer.getAdapterClass():
de.novadata.pp.authenticationdomain.AuthenticationServerAdapter_RMI ###objTransfer.getAdapterMethod(): getAccessTimeExpiration
###objTransfer.getArgumentClass()de.novadata.pp.authenticationdomain.AuthenticationData ###objTransfer.toString():
de.novadata.pp.baseОбжектs.ServletTransferОбжект@f160f16 ###objTransfer.getClass(): class
de.novadata.pp.baseОбжектs.ServletTransferОбжект ###objResult.getClass(): class java.lang.String ###objResult.toString(): 432000000
Это обращение отличается от других только тем, что objResult - это большое число, а не буквенная строка,
но число это, естественно, тоже выдается в виде строки. Из самого objResult мне пока не удалось выудить инфу,
objResult.getClass(), естественно, class java.lang.String.
2. Потом я делаю логин. Идут эти 20 строчек/обращений к сервлету, которые я обозначил выше.
Класс резалта во всех случаях - java.lang.Boolean, а значение - false
Разница между первым обращением:
17.09.2015 12:41:03 I: PP_Servlet (12:41:03):1: objTransfer: objTransfer.getAdapterClass():
de.novadata.pp.authenticationdomain.AuthenticationServerAdapter_RMI ###objTransfer.getAdapterMethod(): getForcedLogOff
###objTransfer.getArgumentClass()de.novadata.pp.authenticationdomain.AuthenticationData ###objTransfer.toString():
de.novadata.pp.baseОбжектs.ServletTransferОбжект@79487948 ###objTransfer.getClass(): class
de.novadata.pp.baseОбжектs.ServletTransferОбжект ###objResult.getClass(): class java.lang.Boolean ###objResult.toString(): false
и вторым:
17.09.2015 12:41:06 I: PP_Servlet (12:41:06):1: objTransfer: objTransfer.getAdapterClass():
de.novadata.pp.authenticationdomain.AuthenticationServerAdapter_RMI ###objTransfer.getAdapterMethod(): getForcedLogOff
###objTransfer.getArgumentClass()de.novadata.pp.authenticationdomain.AuthenticationData ###objTransfer.toString():
de.novadata.pp.baseОбжектs.ServletTransferОбжект@3c623c62 ###objTransfer.getClass(): class
de.novadata.pp.baseОбжектs.ServletTransferОбжект ###objResult.getClass(): class java.lang.Boolean ###objResult.toString(): false
только в значении обжекта, в первом случае это 79487948, во втором - 3c623c62, в третьем - df40df4 и т.д.
В методе sendRequest(Serializable obj) я выдаю в логи следующую инфу:
showInfo("Open connection to servlet: " + m_servlet.toString());
17.09.2015 11:49:19 I: AdapterServlet (11:49:19):Open connection to servlet:
http://sv062919.-----:8160/ICM6/servlet/de.novadata.pp.servlet.ndServlet
showInfo(" sendRequest, Serializable obj: " + out.toString() + " ###" + m_connection.getInputStream());
17.09.2015 12:10:23 I: AdapterServlet (12:10:23): sendRequest, Serializable obj: java.io.ОбжектOutputStream@d38976
###sun.net.www.protocol.http.HttpURLConnection$HttpInputStream@1162a9c
Эта инфа тоже всегда очень похожа, кроме значений типа "@d38976", так что я и тут не могу выделить первый случай обращения к сервлету для логина.
P.S. При первом обращении сервера аутентификации к сервлету нашел-таки одно отличие:
AdapterMethod - getAccessTimeExpiration
А потом, при логине, этот метод getForcedLogOff.
Но теперь юзеры вдруг недовольны, оказывается, они все-таки хотят работать в двух окнах и утверждают, что изначальная проблема возникает и при одном окне, чего я себе представить не могу.
С Явой под вебом я не работал, но думаю принципы остаются такими же.
http://www.coderanch.com/t/362275/Servlets/java/static-avoided-web-app
http://stackoverflow.com/questions/8919095/lifetime-of-asp-net-static-variable
http://blog.aggregatedintelligence.com/2009/01/static-variables-and-their-implic...
http://stackoverflow.com/questions/14154892/scope-of-static-variable-in-multi-us...

Связано ли это с этой статической переменной? Чота я сомневаюсь, честно говоря. Режим секьюрити поставил и там, и там, какие-то переменные окружения или параметры старта RMI штоле повлияли? Теряюсь в догадках.
Очень просто: в init-методе я ставлю статически флаг на true, а в doPost опрашиваю значение этого флага, при true заставляю юзера перелогиниваться в первом окне и ставлю флаг на false
Рука-лицо.
Если вы и правда меняете статическую переменную, то таким макаром залогиниться у вас сможет один-единственный человек. Вообще. Даже с 100500 компьютеров с разными сессиями. До тех пор пока томкат не перегрузит полностью все ваше веб-приложение (надо перегрузить класс).
Один человек логинится, потом логаутится. А второй раз залогинится не сможет. Переменная-то уже установлена.
Тогда статику можно убрать. Или то же самое сделать с аплетом и он будет сингл-тоном, нет?
Вы же вроде мне и другому товарищу говорили про многопоточность и что разные ява-машины и даже разные слои никак друг с другом не связаны.
Хм. А я думал, ее глобальность распространяется только на конкретный сервлет. Разве нет?
Правильный ответ - на все классы, загруженные одним ClassLoader-ом. В простом случае обычного ява-приложения можно все классы считать существующими в одном экземпляре. Для веб-приложения внутри приложения все классы загружены один раз. Чтобы вас не путать дальше рассказывать не буду :)
На конкретный сервлет будут "распространятся" поля объекта. Хотите что-то сохранить между вызовами - сохраняйте в поле объекта. Например, вы хотите посчитать сколько раз на сервлет логинились. private int loginCounter и при каждом логине увеличиваем на единицу.
Тогда статику можно убрать. Или то же самое сделать с аплетом и он будет сингл-тоном, нет?
Апплет у вас во-первых не синглтон, во-вторых он может загружаться разными (процессами) JVM и тогда два инстанса вообще ничего не знают друг о друге.
Вы же вроде мне и другому товарищу говорили про многопоточность и что разные ява-машины и даже разные слои никак друг с другом не связаны.
JVM друг с другом не связаны. А вот что вы сейчас "слоями" назвали я не знаю.
На конкретный сервлет будут "распространятся" поля объекта. Хотите что-то сохранить между вызовами - сохраняйте в поле объекта. Например, вы хотите посчитать сколько раз на сервлет логинились. private int loginCounter и при каждом логине увеличиваем на единицу.
Ну, то есть просто надо убрать static. Я поначалу так и думал, но потом решил все это verschlimmbessern.
Апплет у вас во-первых не синглтон
Но, может быть, его можно сделать таким путем синглтоном?
А то как-то странно получается, все апплеты друг с дружкой незнакомы и пролетают мимо, как непредставленные друг другу англичане, зато один сервлет может изгадить малину всем другим сервлетам :)
Впрочем, да, понимаю, в одном случае один и тот же веб-сервер, в другом - разные ява-машины.
JVM друг с другом не связаны. А вот что вы сейчас "слоями" назвали я не знаю.
Ну, Вы в начале что-то такое говорили. Вот, нашел:
Ну увидит ТС что от двух разных JVM пакеты идут. А может и не увидеть. Можно и внутри одной машины апплеты изолировать.
Ну, то есть просто надо убрать static. Я поначалу так и думал, но потом решил все это verschlimmbessern.
Не-а. Убрав static вы сделаете поиск ошибки "а почему мой клиент то может залогинится то нет" очень увлекательным для тех, кто будет потом пытаться сделать что-то работающее их этого непотребства.
Смотрите. Вообще контейнер создает одну копию вашего сервлета. Т.е. установив флаг на "уже залогинился" даже в поле объекта, и нигде его не возвращая в "разлогинился", вы приходите к тому что у вас было со статическим полем. За одним исключением. Сервлет можно уничтожить и заново пронициализировать. Не надо перегружать всё приложение. Так что да, решение с флагом в поле объекта чем-то лучше чем со статическим полем.
Но. Вообще контейнеры могут создавать и несколько копий сервлета. Особенно если (как это сделано у вас) сервлет объявлен implements SingleThreadModel. Сколько копий - вы повлиять не можете. Какая копия будет обрабатывать какой запрос - тоже. И тут вы можете получить любое поведение да еще и меняющееся от версии контейнера. Поставите новую версию томката, или перейдете на JBoss, WAS еще что-то и ваш сервлет станет работать саавсем по другому.
Вы понимаете к чему вы придете если у вас будут несколько копий сервлета по очереди обрабатывающие запросы? (не каждая копия - свою сессию, а именно по очереди приходящих запросов).
зато один сервлет может изгадить малину всем другим сервлетам
Если запихнете два раза один и тот же класс сервлета в два разных веб-приложения получите полностью независимые друг от друга классы. А можно и тут их связать :) Если архив с классом сервлета запихать не в WAR а в каталог с библиотеками самого томката :)
Можно и внутри одной машины апплеты изолировать.
Угу. Класслоадерами. Классы загруженные разными класслоадерами друг о друге не знают.

Земную жисть пройдя до середины, я оказался в сумрачном лесу.
Странно, что для такой в общем-то обычной и достаточно стандартной проблемы до сих пор нет никакого стандартного решения.
К моему счастью, наши юзеры, похоже, сильно недовольны запретом двух окон и я пока имплементирую другое решение, не связанное с количеством окон. Тем более, что они утверждают, что изначальная проблема проявляется и при одном окне.
Странно, что для такой в общем-то обычной и достаточно стандартной проблемы до сих пор нет никакого стандартного решения.
Нда-с. Стандартное решение (появившееся вместе со спецификациуй сервлетов 1.1 в чтобы не соврать... 98-м что-ли году) - работать с сессиями, передав аутентификацию пользователя контейнеру и уничтожать сессию при неактивности или логауте.
уничтожать сессию при неактивности или логауте.
Но это ведь тоже не решение проблемы, как мы видим, если сессия может делиться "почкованием".
если сессия может делиться "почкованием".
Может быть что угодно. Можно писать свои фильтры, "клапаны", контексты и менеджеры. Но это не значит что это надо делать. В нормальных проектах никаких "делений" сессий не делают.
Ну и я пока что в вашем коде нигде не видел чтобы у вас сессия "почкованием" делилась.
Наверняка ведь какое-то изящное в своей тупизне решение применено :) Но не могу угадать какое.
О, как можно проверить где намудрили - на стороне клиента или сервлета. Вызовите URL вашего сервлета (где ICM6/servlet/ndServlet) просто из адресной строки браузера (желательно другого, не IE, в котором у вас апплет). И посмотрите что у вас в doPost в логи упадет - какое там ID у сессии будет.
А, не выйдет. Надо в doGet скопировать код для отладки - потому как doGet вызовется.
Будет то же самое ID что и у апплета - значит где-то на сервере все же изменен стандартный менеджер сессий. Если другой ID - ну тогда оригинальное решение спрятано в коде апплета.
Посмотрите еще, на всякий случай - у вас никакой класс не имплементирует интерфейс org.apache.catalina.Manager?