[java] вопрос про "подмену" SAX хендлера в сервлете

myrka68

такая ситуация:
есть некий сервлет(скорее всего, это не важно который принимает различные xml-пакеты и как-то на них реагирует.
сейчас это сделано так:

protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
SAXHandler handler = new SAXHandler;
try {
parser.parse(request.getInputStream handler);
}
....
}

до недавнего времени вариация входных xml-пакетов была незначительной, поэтому обработка была сделана в одном хендлере.
что хочется: хочется, чтобы сначала мы поняли, что за xml пришёл (там есть тег для этого а потом "натравили" на него нужный хендлер
наверняка, подмена обработчика - это стандартный механизм
вопрос, как это сделать правильно?

voronetskaya

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

anton7805

по какому пртоколу ходят xml -сообщения? если по http, то тогда слать мессагу с параметрами, а по параметру узнавать какой обработчик подставлять

myrka68

я не специалист по java
что такое "стратс" ?

voronetskaya

если от клиента может придти что-то что-то кроме того xml, то берется банальный стратс и все
но
1) самому клиенту дополнительно указывать тип сложно\некрасиво
2) зачем тогда дублировать инфу о типе в мессаге?

myrka68

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

voronetskaya

http://struts.apache.org
Читать вот это надо -

bastii

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

myrka68

как я понимаю, самая большая проблема в request.getInputStream т.е. xml-файл у нас не статический, а получается по сетке
в впринципе, можно сначала сохранить его в файл на диске, а потом уже обрабатывать, но как-то это некрасиво

bastii

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

bastii

>xml-файл у нас не статический, а получается по сетке
а какая разница?

myrka68

>xml-файл у нас не статический, а получается по сетке
а какая разница?
возможно, я не прав, но я считал, что из request.getInputStream невозможнго читать по второму разу
т.е. после отработки основного хендолера на этом потоке поток станет пустым
а если xml есть в виде файла, то можно сначала разобрать его основных хендлером, определить его тип, а затем повторно разобрать нужным

bastii

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

myrka68

xml имеет следующий формат:

<startxml>
<>
....

<action name='add|get|list|index|search|...'>
.....
</action>
</startxml>

т.е. всё упирается в action
Хотелось бы для каждого типа action иметь свой обработчик, а то в одном уже стало сложно разбираться
если предложишь решение, буду рад

Dasar

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

bastii

а обработка элементов до action зависит от типа action? т.е. их нужно обрабатывать разными хендлерами?

myrka68

до action идёт только авторизация, её не надо в каждом хендлере обрабатывать

myrka68

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

bastii

ну тогда в чем проблема
делаешь хендлер, который обрабатывает все до action
а при обработке action переключаешь парсер на новый хеyдлер, который зависит от типа action

myrka68

в том-то и проблема, что я не знаю, как это сделать
с явой не очень в ладах

bastii

а что у тебя parser? какого типа переменная?

myrka68

javax.xml.parsers.SAXParser parser = javax.xml.parsers.SAXParserFactory.newInstance.newSAXParser;

bastii

заведи в своем основном хендлере поле parser, чтобы ссылаться на парсер
а потом при обработке action попробуй создать другой хендлер и переключится на него
parser.getXMLReader.setContentHandler(newHandler)

myrka68

спасибо!
попробую

bastii

может нужно еще переключить
setDTDHandler(newHandler)
setEntityResolver(newHandler)
setErrorHandler(newHandler)
хотя если они от action не зависят, то и не надо

Hastya

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

Dasar

Фактически ему надо то, что ищет в соседнем треде.

Marinavo_0507

У меня общая задача, а тут частная, которую на java сделать должно быть сильно проще, чем общую.

bastii

ИМХО, тебе надо написать нечто вроде композитного хандлера, который на определенном этапе внутри себя сам переключается на нужную логику.
Надеюсь, ты понял, что я хотел сказать
это тоже что и
А нельзя написать составной хендлер? Типа сначала он смотрит, что за тэг, и в зависимости от него создает нужный хендлер, которому начинает делегировать все методы.

?

Hastya

Да, тоже самое, меня только смутило, что ты потом упомянул "переключить" и всякие методы типа setContentHandler, а тут правильнее именно делегировать и все.

bastii

а что плохого в том, чтобы переключать сам парсер на новый хендлер

Hastya

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

bastii

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

myrka68

всем спасибо
есть ещё один довольно тупой вопрос - что такое "делигирование"?
скорее всего я знаю, что это такое, но в другой терминологии

psm-home

Делегирование. У этого слова несколько значений. В ООП это означает перенаправление сообщений одним объектом другому, уполномоченному.

myrka68

т.е., например, в startElement вставить банальный if на выбор нужного обработчика и вызвать метод этого обработчика с нашими параметрами?

bastii

Да, только обычно без if обходятся. Можно сделать поле в общем хендлере, которое ссылается на другой хендлер, которому хотим делегировать, и сделать реализацию методов, как вызов методов у этого другого хендлера по ссылке через это поле. Тогда, чтобы переключится на новый хендлер, нужно просто записать в поле ссылку на новый хендлер.
Оставить комментарий
Имя или ник:
Комментарий: