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

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> Вопрос по Burlap 
:(
    Опции темы
Zverek
Дата 13.11.2006, 15:56 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



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

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



Здравствуйте!
Пытаюсь написать web-service c помощью Burlap, не могли бы вы мне помочь со следующей ситуацией:
1) На сервере есть класс наследующийся от BurlapServlet
2) На клиете, с помощью BurlapProxyFactory, получаю прокси-объект:
Код

BurlapProxyFactory factory = new BurlapProxyFactory();
Basic basic = (Basic) factory.create(Basic.class, "http://localhost:8084/hello/Hello");

3) Если ещё раз вызвать 
Код

Basic basic2 =  (Basic) factory.create(Basic.class, "http://localhost:8084/hello/Hello")
 
, то он вернёт ссылку на тотже экземпляр прокси-объекта, в то время, как я ожидал, что он создаст на сервере ещё один объект класса "Hello" и даст мне ссылку на связанный с ним прокси.
Вопрос:
Возможно-ли из клиентcкого приложения создавать новые объекты классов, хранящихся на сервере и получать связанные с ними прокси ?

Заранее спасибо за помощь!

PM MAIL   Вверх
tux
Дата 13.11.2006, 16:36 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Летатель
***


Профиль
Группа: Участник Клуба
Сообщений: 1853
Регистрация: 10.2.2005
Где: msk.ru

Репутация: 74
Всего: 132



Почему на клиенте возвращается один и тот же экземпляр прокси объекта не знаю. Burlap использует для этого стандартный класс java.lang.reflect.Proxy, видимо такова его реализация. На сервер связь такая: один экземпляр сервлета - один серверный объект, следовательно, все зависит от веб-контейнера, он тебе может каждый раз возвращать один и тот же зкземпляр, а может наугад выбирать экземпляр из пула сервлетов.
PM MAIL Skype GTalk Jabber YIM   Вверх
Stampede
Дата 13.11.2006, 20:57 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Гносеолог
**


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

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



Цитата(Zverek @  13.11.2006,  05:56 Найти цитируемый пост)
Возможно-ли из клиентcкого приложения создавать новые объекты классов, хранящихся на сервере и получать связанные с ними прокси ?


По правде говоря, сама постановка вопроса вызывает некоторые подозрения: а правильно ли понимается назначение веб сервисов?

Дело в том, что SOA (Service-Oriented Architecture), идеологии которой придерживаются веб сервисы и, в частности, Burlap - это совсем не то, что распределенные вычисления в широком смысле этого слова. SOA - это упрощенная модель распределенного взаимодействия, при которой отдельные сервисы - это точки входа, через которые можно получить ту или иную функциональность или набор функциональных возможностей. Для того чтобы к этим сервисам можно было доступаться извне, они должны иметь какой-то point of reference - то есть адрес, по которому на него можно сослаться. В случае веб сервисов к качестве такого адреса удобно успользовать URL.

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

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

Поэтому давайте сначалаопределимся, о чем вообще у нас идет речь.



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


Новичок



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

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



tux, 
Stampede, Спасибо за подробные объяснения!
Действительно, реализовал работу через один экземпляр сервиса и вышло на мой взгяд правильнее.
Сервисы использую в качестве посредника, при работе клиентского приложения (на Swing'e) с БД. 
В моём случае сервисы выполняют следующие функции:

1) Первый сервис - устанавливает соединение с БД, по запросу от клиента, сохраняет Connection в Map'е и возвращает пользователю номер этого Connection.

2) Второй сервис - ему в качестве параметра передаётся номер соединения, строка SQL запроса. Используя их он создаёт объект, обёртку для Statement, также сохраняет его в Map и возвращает уникальный номер клиенту. Также в этом сервисе реализованы методы для получения стандартных типов данных из Resultset'a - getInt, getString и т.д...

Stampede, влепил бы тебе плюсик, но пока не могу  smile 

Это сообщение отредактировал(а) Zverek - 15.11.2006, 15:52
PM MAIL   Вверх
tux
Дата 15.11.2006, 15:58 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Летатель
***


Профиль
Группа: Участник Клуба
Сообщений: 1853
Регистрация: 10.2.2005
Где: msk.ru

Репутация: 74
Всего: 132



Цитата(Zverek @  15.11.2006,  15:50 Найти цитируемый пост)
Stampede, влепил бы тебе плюсик, но пока не могу  smile 

Будет сделано.
PM MAIL Skype GTalk Jabber YIM   Вверх
Stampede
Дата 16.11.2006, 02:54 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Гносеолог
**


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

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



Цитата(Zverek @  15.11.2006,  05:50 Найти цитируемый пост)
1) Первый сервис - устанавливает соединение с БД, по запросу от клиента, сохраняет Connection в Map'е и возвращает пользователю номер этого Connection.

2) Второй сервис - ему в качестве параметра передаётся номер соединения, строка SQL запроса. Используя их он создаёт объект, обёртку для Statement, также сохраняет его в Map и возвращает уникальный номер клиенту. Также в этом сервисе реализованы методы для получения стандартных типов данных из Resultset'a - getInt, getString и т.д...


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

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

Тут на самом деле имеют место несколько аспектов, но мы начнем с главного - с собственно транзакций. Значит, ты создаешь на сервере датабазное соединение, присваиваешь ему какой-то номер и далее используешь этот номер из клиента. Возникает один маленький вопрос: а кто и когда будет это соединение закрывать? Сервер по запросу клиента? А в какой момент? По выходу из клиентской проги? А если прога зависла? Или вылетела по исключению? А если клиентский программер забыл добавить вызов закрытия соединения?

Ты пойми, что веб-сервис - это штука публичная (даже если и закрытая). К нему нет единого данного на все времена клиента. Для внешнего мира он существует в виде API. И потенциально есть вероятность, что под него будет написано больше одной клиентской программы. И нет никакой гарантии, что клиентский программер будет обязательно продвинутым настолько, чтобы предвидеть все возможные аварийные ситуации.

Поэтому идеологически гораздо правильнее делать демаркацию транзакций на стороне сервера. Это означает, один удаленный вызов - одна транзакция. При таком подходе серверный програмист имеет абсолюный контроль над созданием, фиксацией, откатом и закрытием соединений.

Ну вот скажи, в чем у тебя такая уж сильная неободимость выполнять все датабазные операции, используя одно и то же соединение? Я больше чем уверен, что для твоего случая найдется более надежное решение, не требующее явного управления транзакциями из клиента.
PM WWW   Вверх
Zverek
Дата 16.11.2006, 14:39 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



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

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



Stampede, Ещё раз большое спасибо, за советы!
Да, я действительно задумывался, о том, как закрывать коннект с БД, если допустим клиент потеряет соединение. Сейчас закрываю коннект с БД по выходу из клиентского приложения.
Как вариант хочу попробывать использовать HttpSessionBindingListener - создать класс-обёртку для Connection, реализующий этот интерфейс-листенер. При истечении времени ответа сессии HttpSession оповестит мой объект, и он закроет коннект.
Вычитал такой способ в книжке Bales "Java Programming with Oracle JDBC". Но это написано применительно к сервлетам, у себя ещё не попробывал.

Попробую аргументировать свой выбор:
1) Мое приложение работает следующим образом: в начале работы клиент коннектится к БД (через Веб-сервис), выбирает данные, на их основе создаёт объекты. В процессе дальнейшей работы, при изменении, созданнии или удалении объектов, анналогичные действия выполняются и с записями в БД (т.е. выполняются UPDATE, INSERT, DELETE). НО данные сразу не коммититятся, коммит происходит в тот момент, когда пользователь нажимает кнопку "Сохранить". Если бы у меня коммитилась каждая операция, то действительно для каждой DML операции, можно было бы открывать соединение, и по её выполнении соединение закрывать.

2)Если я правильно понял, то по каждому запросу от клиента, на выполнение DML операции будет открываться отдельное соединение с БД. Не будет ли это сильно нагружать сервер БД и тормозить работу клиента, ведь открытие соединения - операция достаточно трудоёмкая. Пул коннектов тоже не подойдёт т.к. пользователь коннектится к БД под своим именем.

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


Это сообщение отредактировал(а) Zverek - 16.11.2006, 14:43
PM MAIL   Вверх
Stampede
Дата 16.11.2006, 22:11 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Гносеолог
**


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

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



Zverek, очень хорошие вопросы. Приятно общаться с человеком, которому голова дана не только для того чтоб шапку на ней носить smile То, что опыта программного дизайна на Java маловато - это ничего, со временем пройдет.

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

Сразу сообщу хорошую новость: все твои вопросы имеют решения. Просто будь готов к тому, что твои изначальные посылки могут быть не совсем верны. Прежде всего - идея о том, что юзеры должны ходить в базу под своим именем.

Чем  плохи датабазные средства разграничения прав доступа

На самом деле ничем они, конечно, не плохи, но вот использовать и полагаться на них - в данном случае не стОит. Раздельные датабазные логины полностью оправдывали себя в эпоху двухзвенных приложений баз данных - когда гуевый клиент напрямую издавал команды к SQL серверу. В этих условиях другого способа управлять доступом, кроме как устанавливать разным юзерам разные права на уровне объектов СУБД, просто не было в природе.

Но вот на авансцену вышли системы массового обслуживания - в первую очередь веб приложения (но и не только!), и ситуация коренным образом изменилась. Теперь о том, чтобы раздавать каждому юзеру по отдельному датабазному логину, не могло быть и речи. Но дело даже не только в этом. Самое главное, возникла необходимость каким-то образом централизовать датабазную логику. Как ответ на это требование, родилась концепция приложения трехзвенной архитектуры: гуевый клиент - сервер приложения - сервер СУБД.

Это был исключительно важный момент в истории развития компьютерной мысли. Возможность сосредоточить всю логику по обработке данных в одном месте позволила (теретически) создавать приложения намного более пуленепробиваемые, более надежные, более масштабируемые, более удобные в плане управления и развития.

Одним из важнейших следствий такого разделения обязанностей стало то, что теперь клиенту совершенно не нужно было знать о том, где и в каком виде хранятся данные. Это избавило прикладных разработчиков от необходимости кодировать низкоуровневую датабазную логику и позволило им плотнее заняться вопросами собственно пользовательского интерфейса. Так вот, применительно к теме нашего обсуждения, это также означало то, что вся возня с различными датабазными логинами теряла всякий смысл: ведь юзеры теперь ходили в базу не напрямую, а через посредство сервера приложений!

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

Это только кажется, что встроенная в СУБД система разграничения прав доступа - очень мощная и гибкая. В действительности, и особенно в условиях использования СУБД в рамках трехзвенной архитектуры, при организации контроля доступа возникает масса проблем, для которых датабазная секьюрити не может предложить решения. Например:
  • как ограничить доступ к части таблицы на основе некоего условия?
  • как контролировать, что можно и что нельзя модифицировать, если это зависит от значений данных?
  • как контролировать выполнение операций, которые вообще не имеют отношения с СУБД (например, рассылка готовых отчетов)?

Если говоритиь строго, многие из этих вещей таки можно реализовать средствами датабазной секьюрити, но - ценой усложнения структуры самой базы. То есть: база данных и без того вещь непростая - там нужно думать и о производительности, и о конкурентом доступе, и о физическом размещении с учетом требований к масштабированию, копированию/восстановлянию и пр., и  об удобстве программного представления, и еще о куче разных вещей. Если мы в эту картину еще введем всякие извороты, которые диктуются логикой управления доступом, то можем запросто вообще за деревьями потерять из виду сам лес.

Как ответ на перечисленные сложности и ограничения, передовая энетрпрайзная мысль выработала следующий практический подход: коль скоро нам все равно нужна какая-то система аутентификации (грубо говоря, логин/пароль), и привязанная к ней система авторизации (например, доступ к веб страницам) помимо дотабазной, то не проще ли весь контроль над пользовательскими полномочиями вынести вообще за датабазные скобки?

Поэтому в большинстве современных приложений аппсервер ходит в базу под одним и тем же аккаунтом, а для контроля доступа к различным функциональным аспектам приложения использует свою, доморощенную систему разграничения прав. Помимо преимуществ, о которых уже говорилось, это позволяет также без каких-либо проблем использовать единый пул датабазных соединений. Так что будем считать, на вопрос 2) мы ответили. А теперь о главном вопросе:

Цитата(Zverek @  16.11.2006,  04:39 Найти цитируемый пост)
1) Мое приложение работает следующим образом: в начале работы клиент коннектится к БД (через Веб-сервис), выбирает данные, на их основе создаёт объекты. В процессе дальнейшей работы, при изменении, созданнии или удалении объектов, анналогичные действия выполняются и с записями в БД (т.е. выполняются UPDATE, INSERT, DELETE). НО данные сразу не коммититятся, коммит происходит в тот момент, когда пользователь нажимает кнопку "Сохранить". Если бы у меня коммитилась каждая операция, то действительно для каждой DML операции, можно было бы открывать соединение, и по её выполнении соединение закрывать.


Ты понимаешь, что ты сделал? Ты сделал классическое двухзвенное приложение, со всеми присущими ему недостатсками, и облачил его в подобие трехзвенного. Но суть-то осталась та же!

Чем плоха двухзвенка

Самый главный недостаток двухзвенной архитектуры - это то, что операции по доступу к данным со стороны разных клиентов взаимно никак не синхронизированы, и полагаться на помощь в разрешении конфликтов мы можем только на сам сервер СУБД. Что отнюдь не всегда гарантирует нас от ошибок конкурентного доступа. При этом самый худший вид сценария такого рода - это когда пользователю позволяют удерживать открытую транзакцию. Тут у нас открывается самый широкий простор для множественных нежелательных проявлений "фактора ковыряния в носу" (с) мой. Вот навскидку самый простой и совершенно реальный сценарий:
  • Юзер А открыл список кастомеров.
  • Юзер А открыл форму данных кастомера 12345.
  • Юзер А изменил поле PHONE_NUMBER кастомера 12345.
  • Юзера А отвлекли вопросом о стоимости путевок в Анталию, потом позвали на перекур, который плавно перетек в обеденный перерыв.
  • Юзер Б захотел открыть список кастомеров.

Так вот, юзер Б будет очень долго пялиться в курсор "песочные часы", не имея ни малейшего понятия, что происходит и когда это кончится.

Что делать

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

Вообще, то, что ты таскаешь по сети эквиваленты ResultSet, говорит для меня о том, что тебе было бы неплохо ознакомиться с энтерпрайзным паттерном Data Transfer Object (он же Value Object).

И в заключение главное: чем меньше клиент в распределенной системе знает о каких-то там базах данных, тем лучше и надежнее будет работать вся система в целом, и тем крепче и спокойнее будет сон у ее разработчиков smile

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

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

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


 




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


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

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