Академический Документы
Профессиональный Документы
Культура Документы
Аннотация
Rendered by www.RenderX.com
2
Оглавление
1. Об этом руководстве...................................................................................................... 1
1.1. Для кого предназначено руководство.........................................................................1
1.2. Как читать это руководство......................................................................................... 1
1.3. О примерах................................................................................................................... 2
1.3.1. Предварительные требования........................................................................... 2
1.3.2. Запуск примеров..................................................................................................2
1.3.2.1. Требуемое программное обеспечение..................................................... 2
1.3.2.2. Построение примеров................................................................................ 3
1.3.2.3. Настройка примеров...................................................................................3
1.4. Как распечатать это руководство................................................................................3
1.5. Типографские соглашения.......................................................................................... 3
2. Введение в Web-службы................................................................................................ 3
2.1. Значение XML и платформы Java™........................................................................... 4
2.2. Что такое XML?.............................................................................................................5
2.2.1. Что обеспечивает переносимость XML?........................................................... 6
2.3. Обзор Java API для XML..............................................................................................7
2.4. JAXP.............................................................................................................................. 8
2.4.1. SAX API................................................................................................................ 8
2.4.2. DOM API............................................................................................................. 10
2.4.2.1. Пространства имен XML.......................................................................... 12
2.4.3. XSLT API.............................................................................................................13
2.4.3.1. Преобразование дерева DOM в XML-документ.....................................13
2.4.3.2. Преобразование XML-документа в HTML-документ..............................14
2.5. JAX-RPC...................................................................................................................... 15
2.5.1. Обзор JAX-RPC..................................................................................................15
2.5.1.1. Способность к взаимодействию.............................................................. 16
2.5.1.2. Простота использования..........................................................................16
2.5.1.3. Дополнительные функции....................................................................... 17
2.5.2. Использование JAX-RPC.................................................................................. 17
2.5.3. Создание Web-службы......................................................................................18
2.5.4. Кодирование клиентской программы...............................................................19
2.5.5. Вызов удаленного метода................................................................................ 20
2.6. JAXM............................................................................................................................21
2.6.1. Установка соединения...................................................................................... 22
2.6.1.1. Установка соединения точка-точка......................................................... 22
2.6.1.2. Установка соединения с поставщиком системы обмена
сообщениями......................................................................................................... 23
2.6.2. Создание сообщения........................................................................................ 23
2.6.3. Заполнение сообщения.................................................................................... 24
2.6.3.1. Заполнение SOAP-части сообщения...................................................... 24
Web-
Rendered by www.RenderX.com
3
3. Освоение XML...............................................................................................................31
3.1. Введение в XML..........................................................................................................31
3.1.1. Что такое XML?..................................................................................................31
3.1.1.1. Теги и атрибуты........................................................................................ 32
3.1.1.2. Пустые теги............................................................................................... 32
3.1.1.3. Комментарии в XML-файлах................................................................... 33
3.1.1.4. Пролог XML............................................................................................... 33
3.1.1.5. Директивы................................................................................................. 34
3.1.2. В чем важность XML?........................................................................................35
3.1.2.1. Обыкновенный текст................................................................................ 35
3.1.2.2. Идентификация данных........................................................................... 35
3.1.2.3. Стиль отображения.................................................................................. 35
3.1.2.4. Встроенная возможность многократного использования..................... 36
3.1.2.5. Связываемость......................................................................................... 36
3.1.2.6. Простота обработки................................................................................. 36
3.1.2.7. Иерархичность.......................................................................................... 36
3.1.3. Как можно использовать XML?.........................................................................36
3.1.3.1. Традиционная обработка данных........................................................... 37
3.1.3.2. Основанное на документах программирование (DDP)..........................37
3.1.3.3. Связывание............................................................................................... 37
3.1.3.4. Архивация................................................................................................. 38
3.1.3.5. Итог............................................................................................................ 38
3.2. XML и связанные спецификации: освоение алфавитной путаницы...................... 38
3.2.1. Основные стандарты.........................................................................................39
3.2.1.1. SAX............................................................................................................ 39
3.2.1.2. DOM........................................................................................................... 40
3.2.1.3. JDOM и dom4j............................................................................................40
3.2.1.4. DTD............................................................................................................ 40
3.2.1.5. Пространство имен...................................................................................41
3.2.1.6. XSL.............................................................................................................41
3.2.1.7. XSLT (+XPATH)......................................................................................... 41
3.2.2. Стандарты схем.................................................................................................42
Web-
Rendered by www.RenderX.com
4
Web-
Rendered by www.RenderX.com
5
Web-
Rendered by www.RenderX.com
6
5. Web-приложения...........................................................................................................74
5.1. Жизненный цикл Web-приложения........................................................................... 74
5.2. Архивы Web-приложения...........................................................................................76
5.2.1. Структура каталога WAR.................................................................................. 76
5.2.2. Структура каталога примера............................................................................ 76
5.2.3. Создание WAR...................................................................................................77
5.3. Настройка Web-приложений......................................................................................78
5.3.1. Пролог................................................................................................................ 79
5.3.2. Пути псевдонимов............................................................................................. 79
5.3.3. Параметры контекста и инициализации.......................................................... 80
5.3.4. Перехватчики событий...................................................................................... 81
5.3.5. Отображения фильтров.................................................................................... 82
5.3.6. Отображение ошибок........................................................................................ 83
5.3.7. Ссылки на элементы окружения, на элементы окружения ресурсов,
или на ресурсы............................................................................................................ 83
5.4. Установка Web-приложений...................................................................................... 84
5.5. Размещение Web-приложений..................................................................................85
5.6. Просмотр списка установленных и размещенных Web-приложений.....................86
5.7. Выполнение Web-приложений.................................................................................. 86
5.8. Обновление Web-приложений.................................................................................. 86
5.8.1. Перезагрузка Web-приложений........................................................................87
5.8.2. Повторное размещение Web-приложений...................................................... 88
5.9. Удаление Web-приложений.......................................................................................89
5.10. Отмена размещения Web-приложений.................................................................. 89
5.11. Интернационализация и локализация Web-приложений......................................89
5.12. Получение доступа к базам данных из Web-приложений.....................................91
5.12.1. Примеры...........................................................................................................91
5.12.2. Установка и запуск сервера баз данных........................................................91
5.12.3. Заполнение базы данных............................................................................... 92
5.12.4. Настройка в Web-приложении ссылки на источник данных.........................92
5.12.5. Определение источника данных в Tomcat.................................................... 93
5.12.6. Настройка в Tomcat отображения JNDI-имени в источник данных............. 93
5.13. Дополнительная информация.................................................................................94
Web-
Rendered by www.RenderX.com
7
Web-
Rendered by www.RenderX.com
8
Web-
Rendered by www.RenderX.com
9
Web-
Rendered by www.RenderX.com
10
Web-
Rendered by www.RenderX.com
11
Web-
Rendered by www.RenderX.com
12
Web-
Rendered by www.RenderX.com
13
Web-
Rendered by www.RenderX.com
14
Web-
Rendered by www.RenderX.com
15
Web-
Rendered by www.RenderX.com
16
Web-
Rendered by www.RenderX.com
17
Web-
Rendered by www.RenderX.com
18
Web-
Rendered by www.RenderX.com
19
Web-
Rendered by www.RenderX.com
20
Web-
Rendered by www.RenderX.com
21
Web-
Rendered by www.RenderX.com
22
Web-
Rendered by www.RenderX.com
23
Web-
Rendered by www.RenderX.com
24
Web-
Rendered by www.RenderX.com
Для кого предназначено руководство Стр. 1 из 626
1. Об этом руководстве
1.1. Для кого предназначено руководство
Данное руководство предназначено для програмистов, интересующихся разработкой и
размещением Web-служб и Web-приложений с использованием Java WSDP.
Web-
Rendered by www.RenderX.com
Стр. 2 из 626 Об этом руководстве
- Registry Browser
В этой части приведены также схемы кодирования HTTP и Java.
1.3. О примерах
1.3.1. Предварительные требования
Для понимания примеров вы должны хорошо знать язык программирования Java, SQL и
основы реляционных баз данных. Темы, перечисленные в таблице P-1 "Руководства по
Java™" особенно важны:
Таблица P-1. Важные темы в "Руководстве по Java™"
Тема Web-страница
JDBC™ http://java.sun.com/docs/books/tutorial/jdbc
Потоки http://java.sun.com/docs/books/tutorial/essential/threads
JavaBeans™ http://java.sun.com/docs/books/tutorial/javabeans
Безопасность http://java.sun.com/docs/books/tutorial/security1.2
Web-
Rendered by www.RenderX.com
Как распечатать это руководство Стр. 3 из 626
Выбор меню обозначается при помощи символа правой стрелки ->, например, First->Second
следует интерпретировать следующим образом: выберите меню First, затем подменю
Second из меню First.
2. Введение в Web-службы
Web-службы, в общем смысле, представляют собой службы, предлагаемые в Web. В
традиционном сценарии Web-служб бизнес-приложение передает запрос в службу по
определенному URL, используя протокол SOAP по HTTP. Служба принимает запрос,
обрабатывает его и возвращает ответ. Часто приводимым примером Web-службы является
служба котировок акций, в которой запрашивается текущая цена определенной акции.
Цена возвращается в ответе. Это одна из простейших форм Web-службы, в которой ответ
формируется практически сразу, запрос и ответ являются частями одного и того же вызова
метода.
Другим примером может являться служба, определяющая эффективный маршрут доставки
товаров. В этом случае передается запрос, указывающий пункт назначения, а процессы
службы определяют наиболее эффективный маршрут доставки. Время передачи ответа
Web-
Rendered by www.RenderX.com
Стр. 4 из 626 Введение в Web-службы
зависит от сложности маршрутов, то есть ответ может быть передан в виде отдельной от
запроса операции.
Web-службы и потребители Web-служб обычно являются бизнес-процессами,
предназначенными преимущественно для так называемых business-to-business (B-to-B)
транзакций. Предприятие может как предоставлять Web-службы, так и являться
потребителем других Web-служб. Например, оптовый торговец специями может выступать
в роли потребителя при использовании Web-службы для проверки доступности ванильных
зерен, а также в роли поставщика Web-службы во время предложения предполагаемым
потребителям различных цен на зерна от разных поставщиков.
Web-
Rendered by www.RenderX.com
Что такое XML? Стр. 5 из 626
реализующие эти API, а также документация и примеры. Примеры в Java WSDP должны
запускаться в контейнере Tomcat (входящим в пакет Java WSDP), или в J2EE-контейнере
после установки jar-файлов Java WSDP в J2EE SDK. Рекомендации по установка jar-файлов
в J2EE SDK находятся в документации по Java WSDP в каталоге
<JWSDP_HOME>/docs/jwsdponj2ee.html.
В оставшейся части введения дается краткий обзор XML и объясняется, каким образом
эта технология обеспечивает переносимость данных. Затем приводится обзор Java API
для XML, поясняющий, что делают эти API и то, как они облегчают создание Web-
приложений. Каждый API описывается отдельно и затем приводится сценарий, который
демонстрирует их совместную работу.
Последующие руководства дают более детальную информацию и постепенно учат вас
использованию Java API для XML при создании приложений для Web-служб. В них
приводятся также примеры приложений, которые вы можете выполнять.
<priceList>
<coffee>
<name>Mocha Java</name>
<price>11.95</price>
</coffee>
<coffee>
<name>Sumatra</name>
<price>12.50</price>
</coffee>
</priceList>
Теги <coffee> и </coffee> указывают синтаксическому анализатору, что информация между
ними относится к кофе. Два других тега внутри тегов <coffee> указывают, что заключенная
в них информация является названием кофе и его ценой. Поскольку XML-теги указывают
на структуру и содержимое данных, они дают возможность производить такие операции,
как архивирование и поиск.
Вторым основным отличием между XML и HTML является расширяемость XML. При помощи
XML вы можете определять свои собственные теги для описания содержимого конкретного
Web-
Rendered by www.RenderX.com
Стр. 6 из 626 Введение в Web-службы
типа документа. При использовании HTML вы ограничены только теми тегами, которые
определены в спецификации HTML. Вторым аспектом расширяемости XML является
возможность создания файла, называемого схемой и описывающего структуру конкретного
типа XML-документа. Например, можно написать схему для прайс-листа, указывающую,
какие теги могут быть использованы и где они могут находиться. Любой XML-документ
следующий ограничениям, установленным в схеме, считается соответствующим этой
схеме.
Наверное наиболее широко используемый язык схем - это Document Type Definition (DTD),
поскольку он является одной из составных частей спецификации XML 1.0. Написанная на
этом языке схема обычно называется DTD. Приведенная ниже DTD определяет теги,
используемые в XML-документе - прайс-лист. В ней определяются четыре тега (элемента)
и указывается, какие теги могут (или должны) использоваться внутри других тегов. В DTD
также определяется иерархическая структура XML-документа, в том числе и порядок
написания тегов.
Web-
Rendered by www.RenderX.com
Обзор Java API для XML Стр. 7 из 626
Другие особенности делают свой вклад в популярность XML как метода обмена данными.
Одна из них - текстовый формат данных, который легко читается и человеком и текстовыми
редакторами. Приложения могут анализировать и обрабатывать XML-документы, а при
возникновении ошибок при обработке человек может сам прочитать их. Другая особенность
- поскольку XML-документы не содержат инструкций форматирования, они могут быть
отображены различными способами. Хранение данных отдельно от инструкций
форматирования означает, что одни и те же данные могут быть представлены на различных
носителях информации.
XML обеспечивает переносимость документов, но он не может работать в вакууме, то есть,
использующие XML стороны должны согласиться с определенными условиями. Например,
вместе с договоренностью об использовании XML для обмена информацией, два
приложения должны согласовать набор используемых элементов и их значения. При
использовании ими Web-служб, необходимо также согласовать, какие методы Web-служб
будут использоваться, что эти методы будут делать и порядок их вызова в случае
необходимости вызова более одного метода.
Для удовлетворения этих требований предприятиям доступны несколько технологий. Они
могут использовать схемы DTD и XML Schema для описания корректных терминов и XML-
документов, которые будут использоваться при взаимодействии. Средство описания Web-
служб и их методов предоставляют реестры. На более высоком уровне абстракции
предприятия могут использовать партнерские соглашения и схемы рабочих процессов.
Более подробно схемы и реестры рассмотрены ниже.
Web-
Rendered by www.RenderX.com
Стр. 8 из 626 Введение в Web-службы
Еще одной особенностью Java API для XML является их большая гибкость. Для
пользователей - это способы использования API. Например, JAXR-код может использовать
различные средства для обработки XML-документа, а JAXM-код может использовать
различные протоколы обмена сообщениями на верхнем уровне SOAP. Разработчикам
также доступна эта гибкость. Java API для XML определяют жесткие требования по
совместимости для гарантии того, что все реализации предоставляют стандартную
функциональность, но эти API, в то же время, дают разработчикам большую степень
свободы в предоставлении реализаций, адаптированных для конкретных задач.
В следующих главах обсуждаются каждый из этих API.
2.4. JAXP
Java API for XML Processing (JAXP) упрощает обработку XML-данных в приложениях,
написанных на языке программирования Java. JAXP использует особенности стандартов
SAX (Simple API for XML Parsing) и DOM (Document Object Model), то есть вы можете выбрать
между синтаксическим анализом ваших данных как потока событий, или построить
древовидную структуру их представления. Последние версии JAXP поддерживают также
стандарт CSLT (XML Stylesheet Language Transformations), который предоставляет контроль
над способом представления данных и дает возможность преобразования данных в другие
XML-документы или в другие форматы, например HTML. JAXP обеспечивает также
поддержку пространства имен, разрешая работу со схемами, которые могли бы в противном
случае вызвать конфликт имен.
JAXP дает возможность использовать любой XML-совместимый анализатор в вашем
приложении. Это обеспечивается так называемым уровнем подключаемых модулей,
который позволяет вам подключить реализацию SAX или DOM API. Этот уровень позволяет
также подключить XSL-процессор, который может преобразовывать ваши XML-данные
различными способами, в том числе и их внешнее представление.
Последней версией JAXP является JAXP 1.2, в которую добавлена поддержка XML Schema.
Начальная версия JAXP 1.2 включена в данную редакцию Java WSDP и доступна также в
пакете Java XML Pack.
<priceList> [ startElement]
<coffee> [ startElement]
Web-
Rendered by www.RenderX.com
JAXP Стр. 9 из 626
<name>Mocha Java</name> [
startElement,
characters, endElement]
<price>11.95</price> [
startElement,
characters, endElement]
</coffee> [ endElement]
Реализации вызываемых анализатором методов по умолчанию не делают ничего, то есть
вы должны написать подкласс, реализующий соответствующие методы для получения
желаемой функциональности. Например, предположим, что вам нужно получить цену
фунта кофе сорта Mocha Java. Вы должны написать класс, расширяющий DefaultHandler
(реализация ContentHandler по умолчанию), в котором нужно написать ваши собственные
реализации методов startElement и characters.
Прежде всего, необходимо создать объект SAXParser из объекта SAXParserFactory. Вы
будете вызывать его метод parse, передавая прайс-лист и экземпляр вашего нового класса
(с новыми реализациями методов startElement и characters). В данном примере прайс-лист
- это файл, хотя метод parse может также принимать и другие источники входных данных,
включая объект InputStream, URL и объект InputSource.
Web-
Rendered by www.RenderX.com
Стр. 10 из 626 Введение в Web-службы
factory.setValidating(true);
Для того чтобы анализатор знал, какую схему использовать для верификации, XML-документ
должен содержать ссылку на схему в своем объявлении DOCTYPE. Схемой для прайс-
листа является priceList.DTD, то есть, объявление DOCTYPE должно быть примерно таким:
Web-
Rendered by www.RenderX.com
JAXP Стр. 11 из 626
DocumentBuilderFactory factory =
DocumentBuilderFactory.newInstance();
DocumentBuilder builder = factory.newDocumentBuilder();
Document document = builder.parse("priceList.xml");
С этого момента document - это DOM-представление прайс-листа, расположенное в памяти.
В следующем фрагменте кода в прайс-лист добавляется новый сорт кофе (с названием
"Kona" и ценой 13.50). Поскольку мы хотим вставить новый сорт кофе перед сортом "Mocha
Java", первым шагом является получение списка элементов coffee и итерация по списку
для поиска "Mocha Java". При помощи интерфейса Node, включенного в пакет org.w3c.dom,
создается объект Node для нового элемента coffee и новые объекты для элементов name
и price. Элементы name и price содержат символьные данные, поэтому создаются объекты
Text для каждого из них, которые добавляются к объектам Node, представляющим элементы
name и price.
// .
for (int i=0; i < list.getLength(); i++) {
thisCoffeeNode = list.item(i);
Node thisNameNode = thisCoffeeNode.getFirstChild();
if (thisNameNode == null) continue;
if (thisNameNode.getFirstChild() == null) continue;
if (! thisNameNode.getFirstChild() instanceof
org.w3c.dom.Text) continue;
Web-
Rendered by www.RenderX.com
Стр. 12 из 626 Введение в Web-службы
// Mocha Java.
// .
newCoffeeNode.appendChild(newNameNode);
newCoffeeNode.appendChild(newPriceNode);
rootNode.insertBefore(newCoffeeNode, thisCoffeeNode);
break;
}
Обратите внимание, что данный фрагмент кода является упрощенным, поскольку мы
предположили, что не встретим таких элементов как комментарий, атрибут или незначащий
пробел. Информация по более надежному использованию DOM-анализатора находится
в разделе "Повышение сложности".
Можно указать DOM-анализатору проверять документ, точно так же как и SAX-анализатору.
Перед созданием вашего DOM-анализатора нужно вызвать setValidating(true) и проверить,
что анализируемый XML-документ имеет ссылку на свою схему в объявлении DOCTYPE.
Web-
Rendered by www.RenderX.com
JAXP Стр. 13 из 626
<priceList xmlns:nsName="myDTD.dtd"
xmlns:otherNsName="myOtherDTD.dtd">
...
</priceList>
Внутри документа можно указать, к какому пространству имен принадлежит элемент,
например:
<nsName:price> ...
Для того чтобы ваш SAX или DOM-анализатор был способен распознавать пространство
имен, нужно вызвать метод setNamespaceAware(true) вашего экземпляра ParserFactory.
После вызова этого метода любой создаваемый анализатор будет правильно обрабатывать
пространства имен.
TransformerFactory transFactory =
TransformerFactory.newInstance();
Transformer transformer = transFactory.newTransformer();
Используя корневой узел дерева DOM, следующая строка кода создает объект DOMSource,
являющийся источником преобразования.
Web-
Rendered by www.RenderX.com
Стр. 14 из 626 Введение в Web-службы
<xsl:template match="name">
<tr><td>
<xsl:apply-templates/>
</td></tr>
</xsl:template>
В следующей таблице стилей указывается, что XML-данные преобразуются в HTML и
записи о сортах кофе вставляются в строку таблицы.
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="priceList">
<html><head>Coffee Prices</head>
<body>
<table>
<xsl:apply-templates />
</table>
</body>
</html>
</xsl:template>
<xsl:template match="name">
<tr><td>
Web-
Rendered by www.RenderX.com
JAX-RPC Стр. 15 из 626
<xsl:apply-templates />
</td></tr>
</xsl:template>
<xsl:template match="price">
<tr><td>
<xsl:apply-templates />
</td></tr>
</xsl:template>
</xsl:stylesheet>
Для выполнения преобразования необходимо получить XSLT-преобразователь и
использовать его для применения таблицы стилей к XML-данным. В следующем фрагменте
программы создается преобразователь путем создания экземпляра объекта Transformer-
Factory, чтения таблицы стилей и XML-файлов, создания файла для записи HTML и,
наконец, получения объекта Transformer transformer из объекта TransformerFactory tFactory.
TransformerFactory tFactory =
TransformerFactory.newInstance();
String stylesheet = "prices.xsl";
String sourceId = "newXML.xml";
File pricesHTML = new File("pricesHTML.html");
FileOutputStream os = new FileOutputStream(pricesHTML);
Transformer transformer =
tFactory.newTransformer(new StreamSource(stylesheet));
Преобразование завершается вызовом метода transform, в который передаются данные
и выходной поток.
transformer.transform(
new StreamSource(sourceId), new StreamResult(os));
2.5. JAX-RPC
Java API for XML-based RPC (JAX-RPC) - это Java API для разработки и использования
Web-служб.
Web-
Rendered by www.RenderX.com
Стр. 16 из 626 Введение в Web-службы
Web-
Rendered by www.RenderX.com
JAX-RPC Стр. 17 из 626
Web-
Rendered by www.RenderX.com
Стр. 18 из 626 Введение в Web-службы
package coffees;
import java.rmi.Remote;
import java.rmi.RemoteException;
package coffees;
Web-
Rendered by www.RenderX.com
JAX-RPC Стр. 19 из 626
. . .
}
Web-
Rendered by www.RenderX.com
Стр. 20 из 626 Введение в Web-службы
package coffees;
java coffees.CoffeClient
Выполняемый этой строкой кода удаленный вызов процедуры является вызовом
статического метода. Другими словами, RPC был определен во время компиляция.
Web-
Rendered by www.RenderX.com
JAXM Стр. 21 из 626
2.6. JAXM
Java API for XML Messaging (JAXM) предоставляет стандартный способ передачи XML-
документов по сети Интернет из платформы Java. Он базируется на спецификациях SOAP
1.1 и SOAP with Attachments, которые определяют основную среду для обмена XML-
сообщениями. JAXM может быть расширен для работы с протоколами обмена сообщениями
более высокого уровня, например определенным в ebXML (electronic business XML) Message
Service Specification, путем добавления новой функциональности на верхний уровень
SOAP.
Примечание: ebXML Message Service Specification доступна с http://www.oasis-
open.org/committees/ebxml-msg/. Среди других функций этот протокол обеспечивает более
безопасное средство передачи бизнес-сообщений по сети Интернет, чем спецификации
SOAP.
Обычно, бизнес-клиенты используют службу поставщика системы обмена сообщениями,
которая делает всю скрытую работу, требуемую для доставки и маршрутизации сообщений.
При использовании службы поставщика системы обмена сообщениями все JAXM-сообщения
проходят через нее, то есть при передаче сообщения оно сначала направляется к
поставщику отправителя, затем передается поставщику получателя и, наконец, попадает
к адресату. Также существует возможность направления сообщения промежуточным
получателям, прежде чем оно достигнет конечного адресата.
Поскольку сообщения проходят через поставщика, он должен позаботиться о деталях
таких служебных функций как назначение идентификаторов, хранение сообщений и
отслеживание того, доставлялось ли сообщение ранее. Поставщик службы обмена
сообщениями может также попытаться повторно передать сообщение, которое не достигло
назначения с первой попытки. Преимущество использования службы поставщика системы
обмена сообщениями состоит в том, что клиент, применяющий технологию JAXM ("JAXM-
клиент"), абсолютно не должен беспокоиться о том, какую внутреннюю работу делает
поставщик. JAXM-клиент просто вызывает Java-метод, а поставщик, используя свою
инфраструктуру, делает всю остальную работу незаметно для клиента.
Хотя обычно клиенты используют службу поставщика, возможно также осуществлять обмен
JAXM-сообщениями без поставщика. В этом случае, JAXM-клиент (называемый автономным
клиентом) ограничен передачей сообщений типа точка-точка непосредственно в Web-
службу, которая реализует систему обмена сообщениями типа запрос-ответ. Система
запрос-ответ является синхронной, это означает, что передача запроса и прием ответа
происходят в одной и той же операции. Сообщение типа запрос-ответ передается объектом
SOAPConnection через метод SOAPConnection.call, который передает сообщение и
блокирует работу до приема ответа. Автономный клиент может выступать только в роли
клиента, то есть он может только передавать запросы и принимать ответы на них. В отличие
от него JAXM-клиент, использующий службу обмена сообщениями поставщика, может
выступать и в роли клиента и в роли сервера (службы). В роли клиента он передает запросы,
а в роли сервера он может принимать запросы, обрабатывать их и передавать ответы.
Web-
Rendered by www.RenderX.com
Стр. 22 из 626 Введение в Web-службы
SOAPConnectionFactory factory =
SOAPConnectionFactory.newInstance();
Клиент может использовать factory для создания объекта SOAPConnection.
Web-
Rendered by www.RenderX.com
JAXM Стр. 23 из 626
ProviderConnectionFactory pcFactory =
ProviderConnectionFactory.newInstance();
ProviderConnection pcCon = pcFactory.createConnection();
Переменная pcCon представляет собой соединение с реализацией по умолчанию
поставщика службы обмена сообщениями JAXM.
Вторым способом создания объекта ProviderConnection является получение объекта
ProviderConnectionFactory, который нужен для создания соединения с конкретным
поставщиком службы обмена сообщениями. В следующем фрагменте кода показано
получение такого объекта ProviderConnectionFactory и использование его для создания
соединения. Первые две строки используют Java Naming and Directory Interface™ (JNDI)
API для получения соответствующего объекта ProviderConnectionFactory из службы имен,
где он был зарегистрирован под именем "CoffeeBreakProvider". Если это логическое имя
передается в виде аргумента, метод lookup возвращает объект ProviderConnectionFactory,
с которым это имя было связано. Возвращаемое значение имеет тип Java Object и должно
быть переопределено как объект ProviderConnectionFactory для того, чтобы его можно
было использовать для создания соединения. В третьей строке используется JAXM-метод
для получения соединения.
Web-
Rendered by www.RenderX.com
Стр. 24 из 626 Введение в Web-службы
MessageFactory messageFactory2 =
con.createMessageFactory(<schemaURI>);
SOAPMessage m2 = messageFactory2.createMessage();
Каждый из новых объектов SOAPMessage m и m2 автоматически содержит требуемые
элементы SOAPPart, SOAPEnvelope и SOAPBody, плюс необязательный элемент SOAP-
Header (который включен для удобства). Объекты SOAPHeader и SOAPBody первоначально
пусты. В следующем разделе показаны несколько из стандартных способов добавления
в них содержимого.
SOAPPart sp = m.getSOAPPart();
SOAPEnvelope envelope = sp.getSOAPEnvelope();
SOAPBody body = envelope.getSOAPBody();
Web-
Rendered by www.RenderX.com
JAXM Стр. 25 из 626
DocumentBuilderFactory dbf=
DocumentBuilderFactory.newInstance();
DocumentBuilder db = dbf.newDocumentBuilder();
Document doc = db.parse("file:///foo.bar/soap.xml");
DOMSource domSource = new DOMSource(doc);
soapPart.setContent(domSource);
Web-
Rendered by www.RenderX.com
Стр. 26 из 626 Введение в Web-службы
AttachmentPart attachPart =
m.createAttachmentPart("content-string", "text/plain");
m.addAttachmentPart(attachPart);
Третьей альтернативой является создание пустого объекта AttachmentPart и передача
Object и типа его содержимого в метод AttachmentPart.setContent. В данном фрагменте
кода Object имеет тип ByteArrayInputStream и иницилизирован jpeg-изображением.
AttachmentPart ap = m.createAttachmentPart();
byte[] jpegData = ...;
ap.setContent(new ByteArrayInputStream(jpegData),
"image/jpeg");
m.addAttachmentPart(ap);
SOAPMessage response =
soapConnection.call(message, endpoint);
Приложение, использующее службу поставщика системы обмена сообщениями, для
передачи сообщения применяет метод send объекта ProviderConnection. Этот метод
передает сообщение в асинхронном режиме. Это означает, что он передает сообщение
и сразу заканчивает свою работу. Ответ, если таковой есть, будет передан как отдельная
операция в другое время. Обратите внимание, что этот метод принимает только один
параметр - передаваемое сообщение. Поставщик системы обмена сообщениями будет
использовать информацию из заголовка для определения адресата.
providerConnection.send(message);
2.7. JAXR
Java API for XML Registries (JAXR) предоставляет удобный способ получения доступа к
стандартным бизнес-реестрам по сети Интернет. Бизнес-реестры часто описываются как
электронные "желтые страницы", поскольку они содержат списки субъектов бизнеса и
предлагаемые ими продукты и службы. JAXR предоставляет разработчикам, пишущим
приложения на языке программирования Java, унифицированный способ использования
бизнес-реестров, основанных на открытых стандартах (таких как ebXML) или на отраслевых
спецификациях (таких как UDDI).
Web-
Rendered by www.RenderX.com
JAXR Стр. 27 из 626
Субъекты бизнеса могут зарегистрировать себя в реестре или найти других субъектов, с
которыми они, возможно, захотят сотрудничать. Кроме того, они могут предложить
материалы для совместного пользования или найти материалы, предложенные другими.
Группы по разработке стандартов разработали схемы для конкретных типов XML-
документов, и два субъекта бизнеса могут, например, согласиться использовать
стандартную отраслевую схему формы заказа на поставку. Поскольку схема хранится в
стандартном бизнес-реестре оба участника могут использовать JAXR для доступа к ней.
Реестры становятся все более важным компонентом Web-служб, поскольку они дают
возможность субъектам бизнеса взаимодействовать друг с другом динамически или
используя схему слабых связей. Следовательно, потребность в JAXR, позволяющем
предприятиям получать доступ к стандартным бизнес-реестрам из языка программирования
Java, также растет.
RegistryService rs = connection.getRegistryService();
BusinessLifeCycleManager lcm =
rs.getBusinessLifeCycleManager();
BusinessQueryManager bqm =
rs.getBusinessQueryManager();
ClassificationScheme cScheme =
bqm.findClassificationSchemeByName("ntis-gov:naics");
Web-
Rendered by www.RenderX.com
Стр. 28 из 626 Введение в Web-службы
Classification classification =
(Classification)lcm.createClassification(cScheme,
"Snack and Nonalcoholic Beverage Bars", "722213");
org.addClassifications(classifications);
Collection orgs = new ArrayList();
orgs.add(org);
lcm.saveOrganizations(orgs);
//
Collection findQualifiers = new ArrayList();
findQualifiers.add(FindQualifier.CASE_SENSITIVE_MATCH);
Collection namePatterns = new ArrayList();
namePatterns.add("%Coffee%"); // orgs ,
//'Coffee'
// ,
Web-
Rendered by www.RenderX.com
Пример сценария Стр. 29 из 626
2.8.1. Сценарий
Предположим, что владелец сети кофейных магазинов, называемых The Coffee Break,
хочет расширить свою деятельность продажей кофе в интерактивном режиме. Он
приказывает своему бизнес-менеджеру найти несколько новых поставщиков кофе, получить
их оптовые цены и размещать заказы по мере возникновения необходимости. The Coffee
Break может проанализировать цены и принять решение, какие новые сорта кофе
желательно приобретать и у какого из поставщиков.
Web-
Rendered by www.RenderX.com
Стр. 30 из 626 Введение в Web-службы
2.8.2. Заключение
Хотя этот сценарий упрощен в целях краткости, он иллюстрирует, как технологии XML
могут быть использованы в мире Web-служб. С появлением Java API для XML и платформы
J2EE создание Web-служб и написание приложений, использующих их, стали проще.
Web-
Rendered by www.RenderX.com
Введение в XML Стр. 31 из 626
3. Освоение XML
В этой главе описывается Extensible Markup Language (XML) и связанные с ним
спецификации.
<message>
<to>you@yourAddress.com</to>
<from>me@myAddress.com</from>
<subject>XML Is Really Cool</subject>
<text>
How many ways is XML cool? Let me count the ways...
</text>
</message>
Примечание: В этом руководстве жирный шрифт используется для выделения текста, на
который мы хотим обратить ваше внимание. XML не использует жирный шрифт!
Web-
Rendered by www.RenderX.com
Стр. 32 из 626 Освоение XML
Web-
Rendered by www.RenderX.com
Введение в XML Стр. 33 из 626
<?xml version="1.0"?>
Объявление может также содержать дополнительную информацию, например:
Web-
Rendered by www.RenderX.com
Стр. 34 из 626 Освоение XML
3.1.1.5. Директивы
XML-файл может также содержать директивы, которые передают команды или информацию
приложению, обрабатывающему XML-данные. Директивы имеют следующий формат:
<?target instructions?>
где target - имя приложения, которое, как ожидается, будет осуществлять обработку, а
instructions - это строка символов, заключающая в себе информацию или команды для
обработки приложением.
Поскольку директивы зависят от приложения, XML-файл может иметь несколько директив,
указывающих различным приложениям выполнить похожие действия, хотя и разными
способами. XML-файл для слайдшоу, например, может содержать директивы, позволяющие
докладчику выбрать техническую версию презентации или версию для исполнительного
звена. Если бы использовались несколько программ презентации, в программе, возможно,
понадобилось бы наличие нескольких версий директив (хотя было бы лучше, если бы эти
приложения распознавали стандартные директивы).
Примечание: Имя "XML" (в любой комбинации строчных или прописных букв)
зарезервировано для XML-стандартов. В некотором смысле объявление является
директивой, удовлетворяющей стандарту. (Однако, если вы позже будете работать с
анализатором, вы увидите, что метод для обработки директив никогда не видит
объявления.)
Web-
Rendered by www.RenderX.com
Введение в XML Стр. 35 из 626
<to>you@yourAddress.com</to>
может сказать:
1. Начать новую строку.
2. Отобразить "To:" жирным шрифтом с последующим пробелом.
3. Отобразить данные получателя.
Вот что получится:
To: you@yourAddress
Конечно, вы можете сделать тоже самое и в HTML, но вы не сможете обработать данные
программами поиска и программами, извлекающими адреса и т.д. Более важным является
то, что, поскольку XML по своей сути не имеет стиля, вы можете использовать совершенно
разные таблицы стилей для выполнения вывода в форматах postscript, TEX, PDF или
каких-либо новых форматах, которые еще даже не разработаны. Такая гибкость означает
то, что один автор описал как "будущая защита" вашей информации. XML-документы,
созданные сегодня, могут использоваться в будущих, еще не известных системах доставки
документов.
Web-
Rendered by www.RenderX.com
Стр. 36 из 626 Освоение XML
3.1.2.5. Связываемость
Благодаря HTML, способность определять связи между документами рассматривается
сегодня как необходимость. В следующем разделе этого руководства, "XML и связанные
спецификации: освоение алфавитной путаницы", обсуждается программа создания
спецификации по ссылкам. Эта программа позволяет вам определять двунаправленные
ссылки, многоцелевые ссылки, "расширяющиеся" ссылки (в которых переход по ссылке
вызывает появление запрошенной информации в текущем месте документа), и ссылки
между двумя существующими документами, определенные в третьем.
3.1.2.7. Иерархичность
Web-
Rendered by www.RenderX.com
Введение в XML Стр. 37 из 626
3.1.3.3. Связывание
Как только вы определили структуру XML-данных, используя DTD или один из стандартов
схем, большая часть необходимой обработки уже определена. Например, если в схеме
указано, что текстовые данные в элементе <date> должны соответствовать одному из
распознаваемых форматов даты, один из аспектов критерия верификации данных уже
определен - остается только написать код. Хотя спецификация DTD не может обеспечить
такой же уровень детализации, DTD (как и схема) описывает грамматику, указывающую,
какие структуры данных могут встретиться и в какой последовательности. В этой
спецификации указывается, как написать высокоуровневый код, обрабатывающий элементы
данных.
Но когда структура данных (и возможно схема) полностью определена, код, необходимый
вам для обработки этих данных, может быть легко сгенерирован автоматически. Этот
процесс известен под названием связывание - создание классов, распознающих и
обрабатывающих различные элементы данных при обработке спецификации, которая
определяет эти элементы. Со временем вы обнаружите, что используете спецификацию
Web-
Rendered by www.RenderX.com
Стр. 38 из 626 Освоение XML
3.1.3.4. Архивация
Чашей Святого Грааля в программировании является создание повторно используемых,
модульных компонентов. В идеальном случае вы хотели бы взять их с полки, настроить и
подключить их для создания приложения, с минимальным дополнительным кодированием
и дополнительной компиляцией.
Основной механизм сохранения информации называется архивированием. Компонент
архивируется путем записи его в выходной поток в форме, которую можно будет
использовать в дальнейшем. Потом можно будет прочитать его и создать экземпляр,
используя сохраненные параметры. (Например, если вы сохранили элемент таблицы, его
параметрами могут быть количество строк и столбцов для отображения.) Архивированные
компоненты можно перемещать по Web и использовать множеством способов.
Когда компоненты архивируются в бинарной форме, существуют некоторые ограничения
в видах изменений, которые можно сделать в классах при желании сохранить совместимость
с предыдущими версиями. Если бы вы могли модифицировать архивную версию так, чтобы
изменения отразились в ней, это решило бы проблему. Но это очень тяжело сделать с
двоичными объектами. Такие рассуждения вызвали большое количество исследований в
использовании XML для архивирования. Но если состояние объекта было сархивировано
в текстовой форме с использованием XML, тогда все в нем может быть изменено так же
легко, как и сказать "найти и заменить".
Текстовый формат XML может также облегчить передачу объектов между приложениями,
написанными на разных языках. По всем этим причинам основанное на XML архивирование
возможно будет иметь большое распространение в не таком уж далеком будущем.
3.1.3.5. Итог
XML является довольно простым и очень гибким языком разметки. Он имеет много
применений, которые еще должны быть открыты - мы только начинаем использовать его
потенциал. Он является фундаментом для многих грядущих стандартов, обеспечивая
общий язык, который могут использовать различные компьютерные системы для обмена
данными друг с другом. Как только каждая отраслевая группа выйдет со своими
стандартами, компьютеры начнут связываться друг с другом способами, которые раньше
трудно было бы представить.
Более подробная информация по предпосылкам и движущим силам XML находится в
прекрасной статье в Scientific American по адресу
http://www.sciam.com/1999/0599issue/0599bosak.html.
Web-
Rendered by www.RenderX.com
XML и связанные спецификации: освоение алфавитной путаницы Стр. 39 из 626
3.2.1.1. SAX
Простой API для XML.
Этот API был фактически продуктом совместной работы участников списка рассылки XML-
DEV, а не продуктом W3C. Он включен сюда потому, что имеет такие же "окончательные"
характеристики, что и рекомендации W3C.
Вы можете рассматривать этот стандарт как протокол "последовательного доступа" к XML.
Он является быстрым механизмом, который можно применить, например, для чтения или
записи XML-данных на сервер. Его называют также протоколом, управляемым событиями,
поскольку техника работы с ним следующая: регистрация вашего обработчика в SAX-
анализаторе, после чего анализатор обращается к вашим методам обратного вызова при
Web-
Rendered by www.RenderX.com
Стр. 40 из 626 Освоение XML
обнаружении нового XML-тега (либо встречает ошибку, либо хочет передать вам что-нибудь
еще).
Более детальная информация по протоколу SAX находится в разделе "Простой API для
XML".
3.2.1.2. DOM
Document Object Model (объектная модель документа).
Протокол Document Object Model преобразует XML-документ в набор объектов вашей
программы. После этого вы можете манипулировать ими любым способом. Этот механизм
известен также под названием - протокол "произвольного доступа", поскольку можно
обратиться к любой части данных в любое время. Вы можете затем модифицировать
данные, удалить их или вставить новые. Более подробная информация по спецификации
DOM находится в разделе Document Object Model.
3.2.1.4. DTD
Document Type Definition (определение типа документа).
Спецификация DTD является фактически частью спецификации XML, а не отдельной
сущностью. С другой стороны, она не обязательна - вы можете написать XML-документ
без нее. И существует несколько альтернативных стандартов схем, предлагающих более
гибкие возможности. Поэтому DTD рассматривается здесь как отдельная спецификация.
Web-
Rendered by www.RenderX.com
XML и связанные спецификации: освоение алфавитной путаницы Стр. 41 из 626
3.2.1.6. XSL
Extensible Stylesheet Language (расширяемый язык таблиц стилей).
XML-стандарт определяет способ интерпретации данных, а не способ их отображения.
HTML, с другой стороны, определяет, как данные должны быть отображены, без указания
их значения. XSL-стандарт имеет две части, XSLT (стандарт преобразования, описываемый
ниже) и XSL-FO (часть, описывающая объекты форматирования, известные, также, под
названием поток объектов). XSL-FO дает возможность определить различные области на
странице и затем связать их вместе. Когда текстовый поток направляется в такую
коллекцию, текст заполняет полностью первую область, а затем "перетекает" во вторую
область. Такие объекты используются в почтовых рассылках, каталогах и периодических
изданиях.
Последние работы W3C по XSL находятся на странице http://www.w3.org/TR/WD-xsl.
Web-
Rendered by www.RenderX.com
Стр. 42 из 626 Освоение XML
Web-
Rendered by www.RenderX.com
XML и связанные спецификации: освоение алфавитной путаницы Стр. 43 из 626
Для преодоления этих недостатков были сделаны несколько предложений более похожих
на базы данных иерархических схем, определяющих критерии верификации. Основные
предложения обсуждаются ниже.
3.2.2.2. RELAX NG
Regular Language description for XML (описание языка регулярных выражений для XML).
Более простым, чем XML Structure Schema, является появляющийся стандарт под
протекцией OASIS (Organization for the Advancement of Structured Information Systems) -
Организации по развитию структурированных информационных систем. RELAX NG
использует модель регулярных выражений для указания ограничений структурных
взаимосвязей. Этот стандарт разработан для работы с механизмом определения типов
данных XML Schema и указания ограничений их содержимого. Он использует синтаксис
XML и содержит преобразователь DTD в RELAX. ("NG" обозначает "Next Generation". Это
более новая версия механизма схем RELAX, которая интегрирует в себя TREX.)
Дополнительная информация по RELAX NG находится на странице http://www.oasis-
open.org/committes/relax-ng/.
3.2.2.3. TREX
Tree Regular Expressions for XML (дерево регулярных выражений для XML).
Это средство выражения критериев верификации путем описания шаблона структуры и
содержимого XML-документа. Сейчас является частью спецификации RELAX NG.
Дополнительная информация по TREX находится на странице http://www.thaiopen-
source.com/trex/.
3.2.2.4. SOX
Schema for Object-oriented XML (схема для объектно-ориентированного XML).
SOX является схемой, включающей расширяемые типы данных, пространства имен и
встраиваемую документацию.
Дополнительная информация по SOX находится на странице http://www.w3.org/TR/NOTE-
SOX/.
Web-
Rendered by www.RenderX.com
Стр. 44 из 626 Освоение XML
3.2.2.5. Schematron
Схема для объектно-ориентированного XML.
Механизм схемы, основанный на утверждениях и предлагающий комплексную верификацию.
Дополнительная информация по механизму верификации Schematron находится на
странице http://www.ascc.net/xml/resource/schematron/schematron.html.
3.2.3.2. XHTML
Спецификация XHTML - это способ создания XML-документов, которые выглядят и ведут
себя так же как HTML-документы. Поскольку XML-документ может содержать любые теги,
которые вы позаботились определить, почему бы не определить набор тегов, выглядящих
как HTML? Во всяком случае, именно эта идея стоит за спецификацией XHTML. Результатом
применения этой спецификации является документ, который может отображаться в
Web-
Rendered by www.RenderX.com
XML и связанные спецификации: освоение алфавитной путаницы Стр. 45 из 626
3.2.4.1. RDF
Resource Description Framework (среда описаний ресурсов).
RDF является стандартом для определения метаданных - информации, описывающей,
чем является элемент данных и как он может быть использован. Используемый совместно
со спецификацией XHTML например, или с HTML-страницами, RDF может применяться
для описания содержимого страниц. Например, если ваш броузер сохранил вашу
идентификационную информацию как FIRSTNAME, LASTNAME и EMAIL, описание RDF
могло бы сделать возможной передачу данных в приложение, нуждающееся в NAME и
EMAILADDRESS. Только представьте: однажды вам не надо будет вводить имя и адрес
на каждом Web-сайте, который вы посещаете!
Последняя информация по RDF находится на странице http://www.w3.org/TR/REC-rdf-syntax.
3.2.4.3. XTM
XML Topic Maps (карты тем XML).
Являясь по многим параметрам более простым, а также более готовым к использованию
представлением знаний, чем RDF, стандарт Topic Maps заслуживает внимания. До
настоящего времени RDF является стандартом W3C для представления знаний, но карты
тем могут, по-видимому, стать "выбором разработчика" среди стандартов представлений
знаний.
Web-
Rendered by www.RenderX.com
Стр. 46 из 626 Освоение XML
3.2.5.1.1. SMIL
Synchronized Multimedia Integration Language (язык синхронной интеграции мультимедиа).
SMIL - это рекомендация W3C, относящаяся к аудио, видео и анимации. Он также
предназначен для решения сложных вопросов синхронизации воспроизведения этих
элементов.
Дополнительная информация по SMIL находится на странице http://www.w3.org/TR/REC-
smil.
3.2.5.1.2. MathML
Mathematical Markup Language (язык математической разметки).
MathML - это рекомендация W3C, имеющая дело с представлением математических
формул.
Дополнительная информация по MathML находится на странице http://www.w3.org/TR/REC-
MathML.
3.2.5.1.3. SVG
Scalable Vector Graphics (масштабируемая векторная графика).
(Векторные графические изображения строятся на основе команд типа "начертить линию
(квадрат, круг) из точки xi в точку m,n", в отличие от кодирования изображений в виде
последовательности бит. Такие изображения легче масштабируются, хотя обычно они
требуют больше времени обработки для визуализации.)
Дополнительная информация по SVG находится на странице http://www.w3.org/TR/WD-
SVG.
3.2.5.1.4. DrawML
Drawing Meta Language (метаязык для рисования).
DrawML - это комментарий W3C, относящийся к 2D-изображениям для технических рисунков.
Он также предназначен для решения проблемы обновления и повышения качества таких
изображений.
Дополнительная информация по DrawML находится на странице http://www.w3.org/TR/NOTE-
drawml.
Web-
Rendered by www.RenderX.com
XML и связанные спецификации: освоение алфавитной путаницы Стр. 47 из 626
3.2.5.2.1. ICE
Information and Content Exchange (обмен информацией и содержимым).
ICE - это протокол для использования содержимого поставщиками и их подписчиками. Он
сконцентрирован на "автоматизации обмена и повторного использования содержимого,
как в традиционных публикациях, так и B2B-отношениях".
Дополнительная информация по ICE находится на странице http://www.w3.org/TR/NOTE-
ice.
3.2.5.2.2. ebXML
Electronic Business with XML (электронный бизнес с использованием XML).
Этот стандарт предназначен для создания модульной среды электронного бизнеса с
использованием XML. Он является продуктом совместной инициативы организаций United
Nations (UN/CEFACT) и OASIS.
Дополнительная информация по ebXML находится на сайте http://www.ebxml.org/.
3.2.5.2.3. cxml
Commerce XML (коммерческий XML).
cxml - это стандарт RosettaNet (www.rosettanet.org) для настройки интерактивных онлайн-
каталогов для различных покупателей, в которых цены и предложения продуктов зависят
от компании. В него включены механизмы обработки заказов на поставку, изменений
заказов, обновлений состояния и уведомлений о доставке.
Дополнительная информация по cxml находится на сайте http://www.cxml.org/.
3.2.5.2.4. CBL
Common Business Library (библиотека бизнеса общего назначения).
CBL - это библиотека элементов и определений атрибутов, поддерживаемых CommerceNet
(www.commerce.net).
Дополнительная информация по CBL и множеству других инициатив, работающих совместно
в приложениях eCommerce, находится на странице
http://www.commerce.net/projects/currentprojects/eco/wg/eCo_Framework_Specifications.html.
3.2.5.2.5. UBL
Universal Business Library (бизнес-библиотека универсального назначения).
Инициатива OASIS, нацеленная на формирование стандартной библиотеки XML бизнес-
документов (заказов, счетов и т.д.), определяемых в описаниях XML Schema.
Дополнительная информация по UBL находится на странице http://www.oasis-
open.org/committees/ubl.
Web-
Rendered by www.RenderX.com
Стр. 48 из 626 Освоение XML
3.2.6. Итоги
XML становится общепринятым стандартом, используемым в огромном разнообразии
прикладных областей.
<slide>
<title>This is the title</title>
</slide>
либо как:
Web-
Rendered by www.RenderX.com
Разработка структуры данных XML Стр. 49 из 626
Web-
Rendered by www.RenderX.com
Стр. 50 из 626 Освоение XML
Web-
Rendered by www.RenderX.com
Разработка структуры данных XML Стр. 51 из 626
Web-
Rendered by www.RenderX.com
Стр. 52 из 626 Начало работы с Tomcat
4.1. Установка
Примечание: Перед началом работы с приложениями примера просмотрите инструкции
раздела "Об этом руководстве".
Web-
Rendered by www.RenderX.com
Установка Стр. 53 из 626
Web-
Rendered by www.RenderX.com
Стр. 54 из 626 Начало работы с Tomcat
username=your_username
password=your_password
Примечание: По соображениям безопасности сделайте файл build.properties не доступным
для чтения всем, кроме себя.
Файл tomcat-users.xml, который создается установщиком, выглядит примерно так:
<?xml version='1.0'?>
<tomcat-users>
<role rolename="admin"/>
<role rolename="manager"/>
<role rolename="provider"/>
<user username="your_username" password="your_password"
roles="admin,manager,provider"/>
</tomcat-users>
ant build
Ошибки компиляции перечислены в разделе "Ошибки компиляции".
4. Запустите Tomcat, набрав в командной строке следующую команду (см. раздел "Запуск
Tomcat"):
<JWSDP_HOME>/bin/statup.sh ( Unix)
Web-
Rendered by www.RenderX.com
Создание первого приложения Стр. 55 из 626
ant install
Ошибки размещения рассматриваются в разделе "Ошибки размещения".
6. Запустите Web-броузер. Введите следующий URL для запуска примера приложения
(см. раздел "Запуск первого приложения"):
http://localhost:8080/GSApp
7. Остановите Tomcat, набрав следующую команду (см. раздел "Остановка Tomcat"):
<JWSDP_HOME>/bin/shutdown.sh ( Unix)
//ConverterBean.java
package converterApp;
import java.math.*;
Web-
Rendered by www.RenderX.com
Стр. 56 из 626 Начало работы с Tomcat
/** ConverterBean */
public ConverterBean() {
yenRate = new BigDecimal ("138.78");
euroRate = new BigDecimal (".0084");
yenAmount = new BigDecimal("0.0");
euroAmount = new BigDecimal("0.0");
}
public BigDecimal getYenAmount () {
return yenAmount;
}
public void setYenAmount(BigDecimal amount) {
yenAmount = amount.multiply(yenRate);
yenAmount = yenAmount.setScale(2,BigDecimal.ROUND_UP);
}
public BigDecimal getEuroAmount () {
return euroAmount;
}
public void setEuroAmount (BigDecimal amount) {
euroAmount = amount.multiply(euroRate);
euroAmount =
euroAmount.setScale(2,BigDecimal.ROUND_UP);
}
}
4.3.2. Web-клиент
Web-клиент содержится в JSP-странице <JWSDP_HOME>/docs/tutorial/exam-
ples/gs/web/index.jsp. JSP-страница представляет собой текстовый документ, содержащий
статическое и динамическое содержимое. Статическое содержимое - это шаблонные
данные, которые могут быть выражены в любом текстовом формате, таком как HTML,
WML, или XML. Динамическое содержимое создают JSP-элементы.
Web-
Rendered by www.RenderX.com
Создание первого приложения Стр. 57 из 626
<html>
<head>
<title>Currency Conversion Application</title>
</head>
<body bgcolor="white">
"<jsp:useBean id="converter"
class="converterApp.ConverterBean"/>
Web-
Rendered by www.RenderX.com
Стр. 58 из 626 Начало работы с Tomcat
%>
<p><FONT FACE="ARIAL" SIZE=10><%= amount %> dollars are
<%
}
%>
</body>
</html>
Web-
Rendered by www.RenderX.com
Компоновка первого приложения при помощи ant Стр. 59 из 626
Как и makefile, файл build.xml обеспечивает выполнение разных заданий, в том числе и
необязательных (таких как удаление домашнего каталога размещения, что бы вы могли
скомпоновать ваш проект с нуля). Этот файл компоновки включает задания по компиляции
приложения, установке приложения на работающем сервере, перезагрузке
модифицированного приложения на работающем сервере и удаление старых копий
приложения для повторной генерации их содержимого.
При использовании файла build.xml в этом примере для компиляции исходных файлов
создается временный каталог /build в корневом каталоге. Этот каталог содержит точный
образ двоичных установочных файлов вашего Web-приложения. Этот каталог удаляется
и создается заново по необходимости в процессе разработки, так что не редактируйте
файлы в этом каталоге.
<!-
-->
<project name="gs-example" default="build" basedir=".">
<target name="init">
<tstamp/>
</target>
<!-- PATH
-->
<property name="example" value="GSApp" />
<property name="path" value="/${example}"/>
<property name="build"
value="${jwsdp.home}/docs/tutorial/examples/${example}/build"
/>
<!--
Manager -->
<property name="url" value="http://localhost:8080/manager"/>
<property file="build.properties"/>
<property file="${user.home}/build.properties"/>
<!-- Ant
Manager -->
Web-
Rendered by www.RenderX.com
Стр. 60 из 626 Начало работы с Tomcat
<path id="classpath">
<fileset dir="${jwsdp.home}/common/lib">
<include name="*.jar"/>
</fileset>
</path>
<taskdef name="install"
classname="org.apache.catalina.ant.InstallTask" />
<taskdef name="reload"
classname="org.apache.catalina.ant.ReloadTask" />
<taskdef name="remove"
classname="org.apache.catalina.ant.RemoveTask"/>
<!-- -->
Web-
Rendered by www.RenderX.com
Размещение приложения Стр. 61 из 626
</project>
ant build
Эта команда компилирует файлы для ConverterBean. Она размещает создаваемый
файл классов в каталог <JWSDP_HOME>/docs/tutorial/examples/Gapp/build/WEB-
INF/classes/converterApp, как указано в задании build в файле build.xml. Она также
помещает файл index.jsp в каталог GSApp/build и файл web.xml в каталог
GSApp/build/WEB-INF. Tomcat позволяет вам размещать приложение в такой
неупакованной форме. Размещение приложения рассматривается в разделе
"Размещение приложения".
Web-
Rendered by www.RenderX.com
Стр. 62 из 626 Начало работы с Tomcat
<JWSDP_HOME>/bin/statup.sh ( Unix)
Web-
Rendered by www.RenderX.com
Размещение приложения Стр. 63 из 626
ant install
Эта команда копирует файл Web-клиента index.jsp в каталог
<JWSDP_HOME>/docs/tutorial/examples/GSApp/build/ и копирует файл классов
компонента JavaBeans ConverterBean.class в каталог <JWSDP_HOME>/docs/tutorial/exam-
ples/gs/build/WEB-INF/classes/converterApp/.
<JWSDP_HOME>/bin/deploytool
3. В диалоговом окне Set Tomcat Server введите правильное имя пользователя и пароль.
Они устанавливаются при инсталляции Java WSDP или могут быть установлены при
помощи admintool. Информация по установке пользователей при помощи admintool
находится в разделе "Использование admintool".
4. Выберите OK для завершения размещения.
5. Выберите File.
6. Выберите New Web Application.
Отобразится мастер New Web Application. Этот мастер поможет спакетировать Web-
приложение в WAR-файл, определяя индивидуальные Web-компоненты и генерируя
дескриптор размещения для Web-приложения. Мы будем использовать мастер для
идентификации файлов в Web-приложении и для идентификации Web-компонентов в
дескрипторе размещения приложения.
Web-
Rendered by www.RenderX.com
Стр. 64 из 626 Начало работы с Tomcat
<?xmlversion="1.0"encoding="UTF-8"?>
Web-
Rendered by www.RenderX.com
Выполнение первого приложения Стр. 65 из 626
<!DOCTYPEweb-appPUBLIC'-
//SunMicrosystems,Inc.//DTDWebApplication2.3//EN''http://java.
sun.com/dtd/web-app_2_3.dtd'>
<web-app>
<display-name>GSApp</display-name>
<servlet>
<servlet-name>index</servlet-name>
<display-name>index</display-name>
<jsp-file>/index.jsp</jsp-file>
</servlet>
<session-config>
<session-timeout>30</session-timeout>
</session-config>
</web-app>
http://localhost:8080/GSApp
В данной редакции Java WSDP Tomcat требует, чтобы хостом был localhost, который
является компьютером с выполняющимся Tomcat. В данном примере контекстом
приложения является "GSApp". Контекст определяется либо в файле build.xml, либо путем
ввода имени в поле WAR Display Name программы deploytool.
Для проверки приложения:
1. Введите 100 в поле "Enter an amount to convert".
2. Нажмите Submit.
На рисунке 3-1 изображено работающее приложение.
Web-
Rendered by www.RenderX.com
Стр. 66 из 626 Начало работы с Tomcat
<JWSDP_HOME>/bin/shutdown.sh ( Unix)
http://localhost:8080/admin
Эта команда вызывает Web-приложение admin. Перед тем, как вы сможете использовать
это приложение, вы должны добавить ваши имя и пароль и связать с ними роль с
именем admin. Первоначальные имя пользователя и пароль, необходимые для доступа
к этой программе, устанавливаются во время инсталляции Java WSDP. Если вы забыли
имя пользователя и пароль, их можно посмотреть в файле <JWSDP_HOME>/conf/tomcat-
Web-
Rendered by www.RenderX.com
Использование admintool Стр. 67 из 626
users.xml при помощи любого текстового редактора. Этот файл содержит элемент
<user> для каждого конкретного пользователя и может выглядеть примерно так:
Web-
Rendered by www.RenderX.com
Стр. 68 из 626 Начало работы с Tomcat
• Выберите Save.
Web-
Rendered by www.RenderX.com
Общие проблемы и их решение Стр. 69 из 626
Web-
Rendered by www.RenderX.com
Стр. 70 из 626 Начало работы с Tomcat
BUILD FAILED
/home/you/gs/build.xml:44:
java.io.IOException: Server returned HTTP response code: 401
for URL: http://localhost:8080/manager/install?path= ...
Решение: Проверьте, что имя пользователя и пароль в вашем файле build.properties
соответствуют имени пользователя и паролю с назначенной ролью manager в файле
tomcat-users.xml. Дополнительная информация по настройке этой информации находится
в разделе "Создание файла свойств компоновки".
4.9.2.2. Ant Cannot Locate the Build File (ant не может найти файл компоновки)
Симптом: После выполнения команды ant build появляются следующие сообщения:
ant -buildfile
<JWSDP_HOME>/docs/tutorial/examples/gs/build.xml
build
4.9.2.3. The Compiler Cannot Resolve Symbols (компилятор не может разрешить символы)
Симптом: После выполнения команды ant build компилятор отображает множество ошибок,
в том числе и эти:
Web-
Rendered by www.RenderX.com
Общие проблемы и их решение Стр. 71 из 626
Решение: Убедитесь, что вы используете версию ant, поставляемую с Java WSDP. Лучшим
способом дать гарантию, что вы используете нужную версию, является задание полного
пути к файлу ant при построении приложения <JWSDP_HOME>/bin/ant build. Другие версии
могут не иметь функциональности, ожидаемой файлами компоновки приложения примера.
<JWSDP_HOME>/docs/tutorial/examples/gs/build.xml:82:
4.9.2.5. При попытке выполнения задания на установку система, по всем признакам, виснет.
Симптом: После выполнения команды ant install система зависает.
Решение: Начальный сценарий Tomcat запускает сервер в фоновом режиме и сразу же
возвращает пользователя к приглашению командной строки. Даже если вы вернулись в
командную строку, начальный сценарий может не запустить Tomcat полностью. Если
задание по установке не запускается мгновенно, подождите несколько минут и повторите
установку. Для проверки выполнения Tomcat перейдите в вашем броузере на страницу
http://localhost:8080. Когда отобразится начальный экран Tomcat, вы можете продолжать
работу. Если начальный экран не загрузился сразу, подождите несколько минут и повторите
попытку. Если Tomcat все равно не загружается, проверьте log-файлы, как описано ниже,
для получения дальнейшей информации по неисправности.
При запуске Tomcat он инициализируется и загружает Web-приложения из
<JWSDP_HOME>/webapps. Если вы запускаете Tomcat при помощи сценария startup.sh,
сообщения сервера записываются в файл <JWSDP_HOME>/logs/catalina.out. Процесс
загрузки Web-приложений можно посмотреть в файле
<JWSDP_HOME>/logs/jwsdp_log.<date>.txt.
Web-
Rendered by www.RenderX.com
Стр. 72 из 626 Начало работы с Tomcat
4.9.3.4. Ошибка "Build Failed: Application Already Exist at Path" (Компоновка неудачна:
приложение уже существует)
Симптом: После выполнения команды ant install в терминальном окне отображается такое
сообщение:
BUILD FAILED
<JWSDP_HOME>/docs/tutorial/examples/gs/build.xml:82: FAIL -
Это приложение уже установлено. Если вы сделали изменения в приложение после его
установки, используйте команду ant reload для обновления приложения в Tomcat.
4.9.3.5. HTTP 500: No Context Error (HTTP 500: Ошибка: нет контекста)
Симптом: Отображается сообщение No Context Error при попытке запуска размещенного
приложения.
Решение: Эта ошибка означает, что Tomcat загружен, но не знает о вашем приложении.
Если вы не разместили приложение - это будет вашим первым действием. Если вы успешно
разместили приложение при помощи команды ant remove, ant build, ant install и все еще
получаете ошибку - продолжайте чтение.
Web-
Rendered by www.RenderX.com
Дополнительная информация Стр. 73 из 626
Если Tomcat загружен, но не загрузил еще все свои существующие контексты, вы тоже
получите эту ошибку. Продолжайте нажимать кнопки Reload или Refresh вашего броузера,
пока приложение не загрузится или вы не получите какое-либо другое сообщение об
ошибке.
Web-
Rendered by www.RenderX.com
Стр. 74 из 626 Web-приложения
однако, информация в данном руководстве является более новой для версии Tomcat,
поставляемой с Java WSDP.
5. Web-приложения
Web-приложение представляет собой динамическое расширение Web-сервера. Существует
два типа Web-приложений:
• Ориентированные на представление. Ориентированное на представление Web-
приложение в ответ на запрос генерирует динамические Web-страницы, содержащие
различные типы языка разметки (HTML, XML и т.д.).
• Ориентированные на службы. Ориентированное на службы Web-приложение реализует
конечную точку для разделенной на модули Web-службы. Ориентированное на службы
Web-приложение часто вызывается ориентированными на представление приложениями.
В платформе динамическое расширение возможностей Web-сервера Java 2 обеспечивают
Web-компоненты. Web-компонентами являются либо Java-сервлеты, либо JSP-страницы.
Сервлеты представляют собой классы языка программирования Java, которые динамически
обрабатывают запросы и генерируют ответы. JSP-страницы представляют собой текстовые
документы, которые выполняются как сервлеты, но обеспечивают более естественный
подход к созданию статического содержимого. Хотя сервлеты и JSP-страницы
взаимозаменяемы, каждая из этих технологий имеет свои преимущества. Сервлеты больше
подходят для ориентированных на службы Web-приложения и для управления некоторыми
функциями ориентированных на представление приложений, такими как распределение
запросов и обработка нетекстовых данных. JSP-страницы больше подходят для генерации
текстовой разметки, такой как HTML, SVG, WML и XML.
Web-компоненты поддерживаются службами исполняющей платформы, называемой Web-
контейнером. В Java WSDP Web-компоненты выполняются в Web-контейнере Tomcat.
Web-контейнер обеспечивает такие службы как распределение запросов, безопасность,
параллельная работа и управление циклом жизни. Он также предоставляет Web-
компонентам доступ к таким API как служба имен, транзакции и электронная почта.
В этой главе описываются процедуры организации, конфигурации, установки и размещения
Web-приложений. В главах 9 и 10 рассматривается разработка Web-компонентов для
ориентированных на службы Web-приложений. В главах 12 и 13 рассматривается разработка
Web-компонентов для ориентированных на представление Web-приложений. Многие из
возможностей технологии JSP определяются технологией Java Servlet, поэтому вы должны
изучить этот материал, даже если не планируете писать сервлеты.
Большинство Web-приложений используют протокол HTTP, и поддержка HTTP является
важнейшим аспектом Web-компонентов. Краткая сводка возможностей протокола HTTP
приведена в разделе "Обзор HTTP".
Web-
Rendered by www.RenderX.com
Жизненный цикл Web-приложения Стр. 75 из 626
Web-
Rendered by www.RenderX.com
Стр. 76 из 626 Web-приложения
Web-
Rendered by www.RenderX.com
Архивы Web-приложения Стр. 77 из 626
Web-
Rendered by www.RenderX.com
Стр. 78 из 626 Web-приложения
3. Запустите deploytool.
4. Создайте Web-приложение с именем hello1.
A. Выберите File->New Web Application.
B. Выберите Create New Stand-Alone WAR Module.
C. Нажмите Browse и окне выбора файлов перейдите в <JWSDP_HOME>/docs/tuto-
rial/examples/web/hello1.
D. В поле File Name введите hello1.
E. Нажмите Choose Module File.
F. В поле WAR Display Name введите hello1.
Web-
Rendered by www.RenderX.com
Настройка Web-приложений Стр. 79 из 626
5.3.1. Пролог
Поскольку дескриптор размещения представляет собой XML-документ, для него необходим
пролог. Пролог дескриптора размещения Web-приложения выглядит следующим образом:
http://<host>:8080/context_root/alias_path
Перед тем как к сервлету можно будет получить доступ, Web-контейнер должен иметь по
крайней мере один путь псевдонима для компонента. Путь псевдонима должен начинаться
со знака / и заканчиваться строкой или шаблоном с расширением (*.jsp, например).
Поскольку Web-контейнер автоматически отображает путь псевдонима, который
заканчивается *.jsp, вам не обязательно указывать путь псевдонима для JSP-страницы,
пока вы не захотите обратиться к странице по имени, отличному от имени ее файла. В
примере, рассмотренном в разделе "Обновление Web-приложений", страница приветствия
имеет псевдоним, а обращение к response.jsp происходит по имени файла.
Для настройки отображения сервлет-версии приложения Hello в дескрипторе размещения
вы должны добавить в него следующие элементы servlet и servlet-mapping. Чтобы
определить псевдоним для JSP-страницы вы должны заменить субэлемент servlet-class
субэлементом jsp-file в элементе servlet.
Web-
Rendered by www.RenderX.com
Стр. 80 из 626 Web-приложения
<servlet>
<servlet-name>greeting</servlet-name>
<display-name>greeting</display-name>
<description>no description</description>
<servlet-class>GreetingServlet</servlet-class>
</servlet>
<servlet>
<servlet-name>response</servlet-name>
<display-name>response</display-name>
<description>no description</description>
<servlet-class>ResponseServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>greeting</servlet-name>
<url-pattern>/greeting</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>response</servlet-name>
<url-pattern>/response</url-pattern>
</servlet-mapping>
Для настройки отображения сервлет-версии приложения Hello выполните следующие
действия в deploytool:
1. Выберите WAR hello1.
2. Выберите Web-компонент GreetingServlet.
3. Выберите закладку Aliases.
4. Нажмите Add для добавления нового отображения.
5. Введите /greeting в списке псевдонимов.
6. Выберите Web-компонент ResponseServlet.
7. Нажмите Add.
8. Введите /response в списке псевдонимов.
Web-
Rendered by www.RenderX.com
Настройка Web-приложений Стр. 81 из 626
<web-app>
<context-param>
<param-name>
javax.servlet.jsp.jstl.fmt.localizationContext
</param-name>
<param-value>messages.BookstoreMessages</param-value>
</context-param>
...
</web-app>
Для добавления параметра контекста в deploytool выполните следующие действия:
1. Выберите WAR.
2. Выберите закладку Context.
3. Нажмите Add.
Для добавления параметра инициализации в deploytool выполните следующие действия:
1. Выберите Web-компонент.
2. Выберите закладку Init Param.
3. Нажмите Add.
<listener>
<listener-class>listeners.ContextListener</listener-class>
</listener>
Для добавления перехватчика событий в deploytool выполните следующие действия:
1. Выберите WAR.
2. Выберите закладку Event Listeners.
3. Нажмите Add.
4. Выберите класс перехватчика из нового поля в области Event Listener Classes.
Web-
Rendered by www.RenderX.com
Стр. 82 из 626 Web-приложения
<filter>
<filter-name>OrderFilter<filter-name>
<filter-class>filters.OrderFilter<filter-class>
</filter>
<filter-mapping>
<filter-name>OrderFilter</filter-name>
<url-pattern>/receipt</url-pattern>
</filter-mapping>
Чтобы добавить фильтр в deploytool, выполните следующие действия:
1. Выберите WAR.
2. Выберите закладку Filter Mapping.
3. Добавьте фильтр.
A. Нажмите Edit Filter List.
B. Нажмите Add.
C. Выберите класс фильтра.
D. Выберите имя фильтра.
E. Добавьте параметры инициализации фильтра.
F. Нажмите OK.
4. Отобразите фильтр.
A. Нажмите Add.
B. Выберите название фильтра.
C. Выберите тип назначения. Фильтр может быть отображен на конкретный сервлет
или на все сервлеты, соответствующие указанному шаблону URL.
D. Укажите назначение. Если назначение является сервлетом, выберите сервлет из
разворачивающегося списка. Если назначение является шаблоном URL, введите
шаблон.
Web-
Rendered by www.RenderX.com
Настройка Web-приложений Стр. 83 из 626
<error-page>
<exception-type>exception.OrderException</exception-type>
<location>/errorpage.html</location>
</error-page>
Чтобы добавить отображение ошибок в deploytool выполните следующие действия:
1. Выберите WAR.
2. Выберите закладку File Refs.
3. Нажмите Add в области Error Mapping.
4. Введите статус кода HTTP (см. раздел "Ответы HTTP") или полностью указанное имя
класса исключительной ситуации в поле Error/Exception.
5. Введите имя ресурса, который должен быть вызван при возврате кода статуса или
исключительной ситуации. Имя должно начинаться с символа /.
Примечание: Вы можете также определить страницы ошибок для JSP-страницы,
содержащейся в WAR. Если страницы ошибок определены и для WAR, и для JSP-страницы,
страница ошибок для JSP-страницы имеет преимущество.
<resource-ref>
<res-ref-name>jdbc/BookDB</res-ref-name>
<res-type>javax.sql.DataSource</res-type>
<res-auth>Container</res-auth>
</resource-ref>
Чтобы добавить ссылку в deploytool выполните следующие действия:
1. Выберите WAR.
Web-
Rendered by www.RenderX.com
Стр. 84 из 626 Web-приложения
2. Выберите закладку Environment, Enterprise Bean Refs, Resource Env. Refs, или Resource
Refs.
3. Нажмите Add для добавления нового ресурса.
<install url="url"
path="mywebapp" config="file:build/context.xml"
username="username" password="password"/>
Атрибут config указывает файл конфигурации, содержащий элемент context в виде:
<Context path="/bookstore1"
docBase="../docs/tutorial/examples/web/bookstore1/build"
debug="0">
Обратите внимание, что элемент context полностью указывает месторасположение файлов
Web-приложения через свой атрибут docBase.
Файлы компоновки примера руководства содержат задание ant install, которое вызывает
команду ant install:
<target name="install"
description="Install web application" depends="build">
<install url="${url}" path="${mywebapp}"
Web-
Rendered by www.RenderX.com
Размещение Web-приложений Стр. 85 из 626
config="file:build/context.xml"
username="${username}" password="${password}"/>
</target>
Команда ant install требует доступности дескриптора размещения Web-приложения
(web.xml). Все приложения примеров руководства поставляются с дескрипторами
размещения.
Для установки приложения Hello1, описанного в разделе "Жизненный цикл Web-
приложения":
1. В терминальном окне перейдите в каталог <JWSDP_HOME>/docs/tutorial/exam-
ples/web/hello1.
2. Убедитесь, что Tomcat выполняется.
3. Выполните команду ant install. Задание install уведомляет Tomcat о доступности нового
контекста.
Доступны, также, еще два метода размещения, но они требуют перезапуска Tomcat:
• Скопируйте каталог Web-приложения или WAR в <JWSDP_HOME>/webapps.
Web-
Rendered by www.RenderX.com
Стр. 86 из 626 Web-приложения
<Context path="/bookstore1"
docBase="../docs/tutorial/examples/web/
bookstore1/build" debug="0">
Некоторые файлы компоновки примеров содержат задание ant deploy, которое вызывает
команду ant deploy.
http://<host>:8080/manager/list
И, наконец, вы можете просмотреть список выполняющихся на сервере Web-приложений
при помощи deploytool, выбирая сервер из списка Server на левой панели.
http://<host>:8080/hello1/greeting
Замените <host> именем хоста, на котором выполняется Tomcat. Если ваш броузер
выполняется на том же самом хосте, что и Tomcat, вы можете заменить <host> на localhost.
Web-
Rendered by www.RenderX.com
Обновление Web-приложений Стр. 87 из 626
Web-
Rendered by www.RenderX.com
Стр. 88 из 626 Web-приложения
Web-
Rendered by www.RenderX.com
Удаление Web-приложений Стр. 89 из 626
Web-
Rendered by www.RenderX.com
Стр. 90 из 626 Web-приложения
{"TitleCashier", "Cashier"},
{"TitleBookDescription", "Book Description"},
{"Visitor", "You are visitor number "},
{"What", "What We"re Reading"},
{"Talk", " talks about how Web components can transform the way
you develop applications for the Web. This is a must read for
any self respecting Web developer!"},
{"Start", "Start Shopping"},
Для получения нужных строк для данного пользователя Web-компонент извлекает из
запроса значение местности (установленное в настройках языковых предпочтений в
броузере), открывает пакет ресурсов для этой местности и затем сохраняет пакет как
атрибут сессии (см. раздел "Назначение атрибутов сессии"):
ResourceBundle messages =
(ResourceBundle)session.getAttribute("messages");
Web-
Rendered by www.RenderX.com
Получение доступа к базам данных из Web-приложений Стр. 91 из 626
messages.getString("TitleCashier");
Это очень краткое введение в интернационализацию Web-приложений. Для дополнительной
информации по этому вопросу обратитесь к Java BluePrints:
http://java.sun.com/blueprints
5.12.1. Примеры
Примеры, рассматриваемые в главах 12, 13, 15 и 16 используют базу данных. Для этой
редакции мы проверили примеры с базой данных PointBase 4.3 и предоставили файл
компоновки ant для создания таблиц базы данных и заполнения их. Оставшаяся часть
этого раздела описывает как:
• Установить и запустить сервер баз данных PointBase
• Заполнить таблицы примеров
• Настроить Web-приложение для обращения к источнику данных
• Определить источник данных в Tomcat
• Настроить Tomcat для отображения ссылки на источник данных
pb.home=drive:\\<PB_HOME>
2. Скопируйте файл <PB_HOME>/lib/pbclient43.jar в каталог <JWSDP_HOME>/common/lib
для того, чтобы библиотека клиента PointBase стала доступна для приложений
Web-
Rendered by www.RenderX.com
Стр. 92 из 626 Web-приложения
[java] ID
[java] ----------
[java] 201
[java] 202
[java] 203
[java] 204
[java] 205
[java] 206
[java] 207
[java]
[java] 7 Rows Selected.
[java]
[java] SQL>
[java]
[java] COMMIT;
[java] OK
<resource-ref>
<res-ref-name>jdbc/BookDB</res-ref-name>
<res-type>javax.sql.DataSource</res-type>
<res-auth>Container</res-auth>
</resource-ref>
Web-
Rendered by www.RenderX.com
Получение доступа к базам данных из Web-приложений Стр. 93 из 626
http://localhost:8080/admin/index.jsp
2. Зарегистрируйтесь с именем пользователя и паролем, указанными вами при установке
Java WSDP.
3. Выберите запись Data Source в Resources.
4. Выберите Available Actions->Create New Data Source.
5. Введите pointbase в поле JNDI Name.
6. Введите jdbc:pointbase:server://localhost/sample в поле Data Source URL.
7. Введите com.pointbase.jdbc.jdbcUniversalDriver в поле JDBC Driver Class.
8. Введите public в полях User Name и Password.
9. Нажмите кнопку Save.
10. Нажмите кнопку Commit.
<Context path="/bookstore1"
docBase="../docs/tutorial/examples/web/bookstore1/build"
debug="0">
Web-
Rendered by www.RenderX.com
Стр. 94 из 626 Java API for XML Processing
Web-
Rendered by www.RenderX.com
JAXP API Стр. 95 из 626
Web-
Rendered by www.RenderX.com
Стр. 96 из 626 Java API for XML Processing
С другой стороны, создание DOM требует чтения полной XML-структуры и хранения дерева
объектов в памяти, то есть этот метод использует значительно больше ресурсов CPU и
памяти. По этой причине SAX API более предпочтителен для серверных приложений и
фильтров данных, которые не требуют наличия данных в памяти.
И, наконец, XSL API, определенный в javax.xml.transform, позволяет вам записывать XML-
данные в файл или преобразовывать их в другие форматы. И, как вы увидите в разделе
по XSLT этого руководства, вы можете даже использовать его совместно с SAX API для
преобразования обычных данных в XML.
Анализатор содержит в себе объект SAXReader. При вызове метода анализатора parse()
считыватель вызывает один из нескольких методов обратного вызова, реализованных в
приложении. Эти методы определяются интерфейсами ContentHandler, ErrorHandler,
DTDHandler и EntityResolver.
Вот сводка ключевых SAX API:
SAXParserFactory
Объект SAXParserFactory создает экземпляр анализатора, определенного системным
свойством javax.xml.parsers.SAXParserFactory.
SAXParser
Интерфейс SAXParser определяет методы parse() нескольких типов. В обычном случае,
вы передаете источник XML-данных и объект DefaultHandler анализатору, который
обрабатывает XML и вызывает соответствующие методы объекта handler.
SAXReader
SAXParser включает в себя SAXReader. Обычно, вам не надо беспокоиться об этом, но
изредка необходимо использовать метод getXMLReader() объекта SAXParser для настройки
Web-
Rendered by www.RenderX.com
The Simple API for XML (SAX) Стр. 97 из 626
Web-
Rendered by www.RenderX.com
Стр. 98 из 626 Java API for XML Processing
Пакет Описание
org.xml.sax Определяет SAX-интерфейсы. Имя org.xml является
префиксом пакета, который был разработан группой,
определившей SAX API.
org.xml.sax.ext Определяет расширение SAX, использующееся при более
сложной SAX-обработке, например, для обработки
определений типа документа (DTD) или для просмотра
детального синтаксиса файла.
org.xml.sax.helpers Содержит вспомогательные классы, облегчающие
использование SAX - например, определяя обработчик по
умолчанию, который имеет null-методы для всех
интерфейсов, так что вам необходимо переопределить только
те из них, которые действительно нужны.
javax.xml.parsers Определяет класс SAXParserFactory, возвращающий
SAXParser. Также определяет классы исключительных
ситуаций для вывода ошибок.
Web-
Rendered by www.RenderX.com
XML Stylesheet Language Transformations API (XSLT) Стр. 99 из 626
пользователи, ожидающие объекты, обычно удивлены, когда при вызове метода text()
объекта element ничего не возвращается. Действительно объектно-ориентированное
дерево используется в JDOM API, информацию по которому можно найти на сайте
http://www.jdom.org.
Web-
Rendered by www.RenderX.com
Стр. 100 из 626 Java API for XML Processing
Объект result представляет собой результат процесса преобразования. Этот объект может
быть обработчиком событий SAX, DOM, или выходным потоком.
Объект transformer может быть создан из набора инструкций преобразования, в этом
случае проводятся указанные преобразования. Если transformer создан без указания каких-
либо инструкций, то он просто копирует source в result.
Web-
Rendered by www.RenderX.com
Куда идти дальше? Стр. 101 из 626
Web-
Rendered by www.RenderX.com
Стр. 102 из 626 Simple API for XML
Web-
Rendered by www.RenderX.com
Написание простого XML-файла Стр. 103 из 626
Web-
Rendered by www.RenderX.com
Стр. 104 из 626 Simple API for XML
<slideshow>
</slideshow>
Примечание: Имена XML-элементов чувствительны к регистру символов. Завершающий
тег должен в точности соответствовать начальному тегу.
...
<slideshow
>
</slideshow>
При создании имени тега или атрибута можно использовать дефисы ("-"), знаки
подчеркивания ("_"), двоеточия (":") и точку (".") в дополнение к символам и цифрам. В
отличие от HTML значения XML-атрибутов всегда находятся в кавычках, а несколько
атрибутов никогда не разделяются запятой.
Примечание: Двоеточия должны использоваться с осторожностью или вообще не
использоваться, поскольку они применяются при определении пространства имен для
XML-документа.
<slideshow
...
>
Web-
Rendered by www.RenderX.com
Написание простого XML-файла Стр. 105 из 626
<slide type="all">
<title>Wake up to WonderWidgets!</title>
</slide>
</slideshow>
Здесь также был добавлен атрибут type к элементу slide. Назначение этого атрибута
следующее - слайды могут быть отмечены для показа технической или исполнительной
аудитории (type="tech" или type="exec"), а также идентифицированы подходящими обеим
аудиториям (type="all").
Более важно, что этот пример иллюстрирует различие между объектами, которые лучше
определить элементами (элемент title), и объектами, которые лучше определить атрибутами
(атрибут type). Здесь работает эвристический подход, основанный на видимости. title - это
то, что аудитория будет видеть. Поэтому он является элементом. type, с другой стороны,
- это то, что никогда не будет показано, поэтому это - атрибут. Другим способом это
различие можно объяснить так - элемент является контейнером, наподобие бутылки. type
- это характеристика контейнера (длинный он или короткий, широкий или узкий). title - это
характеристика содержимого (вода, молоко или чай). Это, естественно, не жесткие, быстро
применимые правила, но они могут помочь вам при разработке своих собственных XML-
структур.
...
<!-- TITLE SLIDE -->
<slide type="all">
<title>Wake up to WonderWidgets!</title>
</slide>
Web-
Rendered by www.RenderX.com
Стр. 106 из 626 Simple API for XML
</slideshow>
Далее мы увидим, что определение элемента title вступает в конфликт с элементом XHTML,
использующим такое же имя. Мы рассмотрим механизм, вызывающий конфликт (DTD), и
несколько возможных решений в разделе "Анализ и параметризованные DTD".
...
<!-- OVERVIEW -->
<slide type="all">
<title>Overview</title>
<item>Why <em>WonderWidgets</em> are great</item>
<item/>
</slideshow>
Обратите внимание, что любой элемент может быть пустым элементом. Все что для этого
необходимо - закончить тег знаками "/>", а не ">". Можно сделать то же самое путем ввода
<item></item>, что является эквивалентом.
Примечание: Другим фактором, делающим XML-файл формально-правильным, является
правильное вложение. То есть, <b><i>some_text</i></b> является формально-правильным,
поскольку последовательность <i>…</i> полностью вложена в тег <b>…</b>. Следующая
последовательность не является формально-правильной: <b><i>some_text</b></i>.
Web-
Rendered by www.RenderX.com
Дублирование XML-файла при помощи SAX-анализатора Стр. 107 из 626
<slideshow
title="Sample Slide Show"
date="Date of publication"
author="Yours Truly"
>
Web-
Rendered by www.RenderX.com
Стр. 108 из 626 Simple API for XML
}
Поскольку мы собираемся выполнять ее автономно, нам необходим метод main. И нам
необходимы аргументы командной строки, чтобы указать приложению, в какой файл
осуществлять вывод.
import java.io.*;
import org.xml.sax.*;
import org.xml.sax.helpers.DefaultHandler;
import javax.xml.parsers.SAXParserFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.parsers.SAXParser;
if (argv.length != 1) {
System.err.println("Usage: cmd filename");
Web-
Rendered by www.RenderX.com
Дублирование XML-файла при помощи SAX-анализатора Стр. 109 из 626
System.exit(1);
}
try {
//
out = new OutputStreamWriter(System.out, "UTF8");
}
catch (Throwable t) {
t.printStackTrace();
}
System.exit(0);
{
...
}
Web-
Rendered by www.RenderX.com
Стр. 110 из 626 Simple API for XML
//
SAX-
DefaultHandler handler = new Echo();
//
( )
SAXParserFactory factory = SAXParserFactory.newInstance();
try {
//
out = new OutputStreamWriter(System.out, "UTF8");
//
SAXParser saxParser = factory.newSAXParser();
saxParser.parse( new File(argv[0]), handler );
} catch (Throwable t) {
t.printStackTrace();
}
Web-
Rendered by www.RenderX.com
Дублирование XML-файла при помощи SAX-анализатора Стр. 111 из 626
System.exit(0);
}
При помощи этих строк кода вы создали экземпляр SAXParserFactory, как определено в
установках системного свойства javax.xml.parsers.SAXParserFactory. Затем вы получили
экземпляр анализатора этого класса для обработки событий анализа и указали входной
файл для обработки.
Примечание: Класс javax.xml.parsers.SAXParser является оболочкой, в которой определяется
несколько удобных методов. Он включает в себя (немного менее дружественный) объект
org.xml.sax.Parser. При необходимости можно получить этот анализатор при помощи метода
getParser() объекта SAXParser.
Теперь вы просто перехватываете любые исключительные ситуации, которые анализатор
может сгенерировать. Более подробно обработку ошибок вы изучите в последнем разделе
этого руководства "Обработка ошибок неверифицирующим анализатором".
...
При вызове emit любая ошибка ввода/вывода перехватывается в SAXException вместе с
сообщением, идентифицирующим ее. Затем эта исключительная ситуация передается
назад в SAX-анализатор. Далее вы изучите исключительные ситуации SAX более подробно.
А пока имейте в виду, что emit - это маленький метод, который обрабатывает вывод строк.
(Вы увидите, что он часто вызывается в коде.)
Web-
Rendered by www.RenderX.com
Стр. 112 из 626 Simple API for XML
}
Примечание: Немного досадно, но вам придется вызывать nl() много раз. Определение
его сейчас упростит код в дальнейшем. Он также обеспечивает место для вставки отступов
при выводе.
Web-
Rendered by www.RenderX.com
Дублирование XML-файла при помощи SAX-анализатора Стр. 113 из 626
Web-
Rendered by www.RenderX.com
Стр. 114 из 626 Simple API for XML
}
}
emit(">");
}
StringBuffer textBuffer;
Web-
Rendered by www.RenderX.com
Дублирование XML-файла при помощи SAX-анализатора Стр. 115 из 626
...
Затем добавьте выделенный ниже код для сбора символов, переданных анализатором, в
буфер:
Web-
Rendered by www.RenderX.com
Стр. 116 из 626 Simple API for XML
Web-
Rendered by www.RenderX.com
Дублирование XML-файла при помощи SAX-анализатора Стр. 117 из 626
javac Echo.java
java Echo slideSample.xml
В версии 1.4 платформы Java 2 необходимо идентифицировать JAR-файлы как более
новые версии "рекомендованных стандартов", которые встроены в платформу Java 2. Для
этого разместите JAR-файлы в каталоге рекомендованных стандартов - jre/lib/endorsed.
(Скопируйте все JAR-файлы, кроме jaxp-api.jar. Его можно проигнорировать, поскольку
JAXP API уже встроен в платформу Java 2 версии 1.4.)
Затем можно откомпилировать и запустить программу при помощи следующих команд:
javac Echo.java
java Echo slideSample.xml
Web-
Rendered by www.RenderX.com
Стр. 118 из 626 Simple API for XML
...
<slideshow title="Sample Slide Show" date="Date of publication"
author="Yours Truly">
<slide type="all">
<title>Wake up to WonderWidgets!</title>
</slide>
...
Примечание: Выводимая программой информация находится в файле Echo01-01.txt.
(Версия для броузера - Echo01.01.html.)
При взгляде на эту информацию возникает несколько вопросов. А именно, откуда
появляются лишние пустые строки? И почему элементы располагаются с правильными
отступами, хотя в коде для этого ничего не делалось? Мы ответим на эти вопросы. Прежде
всего, необходимо сделать несколько замечаний о выводимой информации:
• Комментарии, определенные в начале файла
<!-- A SAMPLE set of slides -->
не появляются в листинге. Комментарии будут игнорироваться до тех пор, пока вы не
реализуете LexicalHandler. Более подробно этот вопрос рассмотрен ниже.
• Атрибуты элемента перечисляются все вместе на одной строке. Если ваше окно
недостаточно широко, вы можете их всех не увидеть.
• Определенный вами пустой элемент (<item/>) выводится как пустой элемент из двух
тегов (<item></item>). Они в любых случаях идентичны. (Просто первый легче набирать
и он занимает меньше места.)
Web-
Rendered by www.RenderX.com
Дублирование XML-файла при помощи SAX-анализатора Стр. 119 из 626
Web-
Rendered by www.RenderX.com
Стр. 120 из 626 Simple API for XML
emit("\t\"");
emit(attrs.getValue(i));
emit("\"");
}
}
if (attrs.getLength() > 0) nl();
emit(">");
}
...
CHARS: |
Web-
Rendered by www.RenderX.com
Дублирование XML-файла при помощи SAX-анализатора Стр. 121 из 626
Web-
Rendered by www.RenderX.com
Стр. 122 из 626 Simple API for XML
...
Web-
Rendered by www.RenderX.com
Дублирование XML-файла при помощи SAX-анализатора Стр. 123 из 626
Вы, наверно, будете счастливы узнать, что вы достигли конца "механического" кода,
который нужно было добавить в программу Echo. С этого момента вы будете выполнять
работу, которая позволит понять внутреннюю работу анализатора, хотя действия, которые
вы уже выполнили, дали понимание того, как анализатор видит обрабатываемые XML-
данные. Вы также научились использовать полезное средство отладки для просмотра
того, что видит анализатор.
ELEMENT: <slideshow
...
>
CHARS:
CHARS:
ELEMENT: <slide
...
END_ELM: </slide>
CHARS:
CHARS:
Примечание: Выходная информация в полном виде находится в файле Echo03-01.txt.
(Версия для броузера - Echo03-01.html).
Обратите внимание на то, что метод characters вызывается дважды для каждой строки.
Исследование исходного файла slideSample01.xml показывает, что перед первым слайдом
есть комментарий. Первый вызов characters приходит перед этим комментарием. Второй
вызов - после. (Далее вы увидите, как можно получить уведомление о встрече анализатором
комментария, хотя в большинстве случаев оно вам не нужно.)
Обратите внимание, что метод characters вызывается после первого элемента slide, так
же как и перед ним. Если рассуждать с точки зрения иерархически структурированных
данных - это кажется странным. В конце концов, вы ожидали, что элемент slideshow
содержит элементы slide, а не текст. Дальше вы увидите, как ограничить элемент slideshow
при помощи DTD. После этого метод characters не будет больше вызываться.
При отсутствии DTD анализатор должен предположить, что любой элемент, который он
видит, содержит текст, как первый элемент item в рассматриваемом примере:
ELEMENT: <item>
CHARS: Why
ELEMENT: <em>
CHARS: WonderWidgets
Web-
Rendered by www.RenderX.com
Стр. 124 из 626 Simple API for XML
END_ELM: </em>
CHARS: are great
END_ELM: </item>
Web-
Rendered by www.RenderX.com
Добавление дополнительных обработчиков событий Стр. 125 из 626
throws SAXException
{
if (textBuffer != null) {
echoText();
textBuffer = null;
}
String s = new String(buf, offset, len);
...
}
Затем добавьте выделенный ниже метод в программу Echo для получения локатора
документа и используйте его для вывода системного ID документа:
...
private String indentString = " "; //
Web-
Rendered by www.RenderX.com
Стр. 126 из 626 Simple API for XML
LOCATOR
SYS ID: file:<path>/../samples/slideSample01.xml
START DOCUMENT
<?xml version='1.0' encoding='UTF-8'?>
...
Отсюда видно, что setDocumentLocator вызывается перед startDocument. Это может иметь
значение в случаях, когда вы проводите какую-либо инициализацию в коде обработки
событий.
<slideshow
...
>
Web-
Rendered by www.RenderX.com
Добавление дополнительных обработчиков событий Стр. 127 из 626
• Для улучшения читаемости хорошей идеей является помещение двоеточия (:) после
имени приложения, например:
<?my.presentation.Program: QUERY="..."?>
Двоеточие подчеркивает, что имя назначения является "меткой", указывающей
получателя команды. Однако, хотя спецификация w3c разрешает использование
двоеточия в имени назначения, некоторые версии IE5 считают это ошибкой. В данном
руководстве мы будем стараться не использовать двоеточия в имени назначения.
Теперь, когда вы имеете команду обработки, с которой можно работать, добавьте
выделенный ниже код в приложение Echo:
ELEMENT: <slideshow
...
>
PROCESS: <?my.presentation.Program QUERY="exec, tech, all"?>
CHARS:
...
7.4.3. Резюме
За исключением метода ignorableWhitespace вы использовали большинство методов
ContentHandler, которые были необходимы для управления наиболее полезными SAX-
событиями. Вы изучите использование ignorableWhitespace немного позднее. Далее вы
получите более глубокие знания в обработке ошибок, возникающих в процессе SAX-анализа.
Web-
Rendered by www.RenderX.com
Стр. 128 из 626 Simple API for XML
...
<!-- OVERVIEW -->
<slide type="all">
<title>Overview</title>
<item>Why <em>WonderWidgets</em> are great</item>
<item/>
<item>Who <em>buys</em> WonderWidgets</item>
</slide>
...
в результате получится:
...
<item>Why <em>WonderWidgets</em> are great</item>
<item>
<item>Who <em>buys</em> WonderWidgets</item>
...
Web-
Rendered by www.RenderX.com
Обработка ошибок в неверифицирующем анализаторе Стр. 129 из 626
org.xml.sax.SAXParseException:
The element type "item" must be terminated by the
matching end-tag "</item>".
...
at org.apache.xerces.parsers.AbstractSAXParser...
...
at Echo.main(...)
Примечание: Приведенное выше сообщение сгенерировано библиотеками JAXP 1.2. Если
вы используете другой анализатор, сообщение об ошибке, возможно, будет другим.
При возникновении фатальной ошибки анализатор не сможет продолжать работу. Поэтому,
если приложение не генерирует исключительную ситуацию (вы вскоре увидите, как это
сделать), то ее сгенерирует обработчик ошибок событий по умолчанию. Стек трассировки
генерируется обработчиком исключительных ситуаций Throwable в вашем методе main:
...
} catch (Throwable t) {
t.printStackTrace();
}
Этот стек трассировки не очень полезен. Далее вы увидите, как генерировать более
хорошую диагностику при возникновении ошибок.
...
} catch (SAXParseException spe) {
// ,
System.out.println("\n** Parsing error"
+ ", line " + spe.getLineNumber()
+ ", uri " + spe.getSystemId());
System.out.println(" " + spe.getMessage() );
Web-
Rendered by www.RenderX.com
Стр. 130 из 626 Simple API for XML
} catch (Throwable t) {
t.printStackTrace();
}
Сейчас при выполнении программы выдается немного более полезная информация об
ошибке:
Web-
Rendered by www.RenderX.com
Обработка ошибок в неверифицирующем анализаторе Стр. 131 из 626
...
} catch (SAXParseException err) {
System.out.println("\n** Parsing error"
+ ", line " + err.getLineNumber()
+ ", uri " + err.getSystemId());
System.out.println(" " + err.getMessage());
} catch (Throwable t) {
t.printStackTrace();
}
Этот код проверяет, содержит ли SAXException в себе другую исключительную ситуацию.
Если да, то генерирует стек трассировки, начиная с места, где произошла исключительная
ситуация, для точного определения кода, вызвавшего ошибку. Если исключительная
ситуация содержит только сообщение, код распечатывает стек трассировки начиная с
места, где была сгенерирована исключительная ситуация.
...
} catch (SAXParseException err) {
System.out.println("\n** Parsing error"
+ ", line " + err.getLineNumber()
+ ", uri " + err.getSystemId());
System.out.println(" " + err.getMessage());
Web-
Rendered by www.RenderX.com
Стр. 132 из 626 Simple API for XML
//
// ,
Exception x = spe;
if (spe.getException() != null)
x = spe.getException();
x.printStackTrace();
// ( )
Exception x = sxe;
if (sxe.getException() != null)
x = sxe.getException();
x.printStackTrace();
} catch (Throwable t) {
t.printStackTrace();
}
Теперь программа готова к обработке любой возможной исключительной ситуации при
SAX-анализе. Вы увидели, что для фатальных ошибок анализатор генерирует
исключительные ситуации. Но для не фатальных ошибок и предупреждений обработчик
ошибок по умолчанию никогда не генерирует исключительных ситуаций, и никакие
сообщения не выводятся. Через минуту вы изучите более подробно ошибки и
предупреждения, а также узнаете, как создавать обработчик ошибок для их обработки.
Web-
Rendered by www.RenderX.com
Обработка ошибок в неверифицирующем анализаторе Стр. 133 из 626
pce.printStackTrace();
} catch (Throwable t) {
t.printStackTrace();
Конечно, существует довольно много обработчиков ошибок. Но, по крайней мере, вы знаете
типы исключительных ситуаций, которые могут произойти.
Примечание: Если класс генератора, указанный в системном свойстве, не может быть
найден или создан, может сгенерироваться также javax.xml.parsers.FactoryConfigurationError.
Это неперехватываемая ошибка, поскольку программа не может продолжать выполнение
после нее.
pce.printStackTrace();
} catch (Throwable t) {
...
Мы выйдем из обработчика для Throwables для перехвата ошибок нулевых указателей,
но обратите внимание, что в этом месте он делает то же самое, что и обработчик IOExcep-
tion. Здесь мы просто демонстрируем типы исключительных ситуаций, которые могут
произойти, в случае если после них ваше приложение способно продолжать выполнение.
Web-
Rendered by www.RenderX.com
Стр. 134 из 626 Simple API for XML
//
public void error(SAXParseException e)
throws SAXParseException
{
throw e;
}
Примечание: Полезно проанализировать методы обработки ошибок, определенные в
org.xml.sax.helpers.DefaultHandler. Вы увидите, что методы error() и warning() не делают
ничего, а fatalError() генерирует исключительную ситуацию. Кончено, вы всегда можете
переопределить метод fatalError() для генерации другой исключительной ситуации. Но
если ваш код не генерирует исключительную ситуацию при возникновении фатальной
ошибки, это сделает SAX-анализатор - так требует спецификация XML.
Web-
Rendered by www.RenderX.com
Замена и вставка текста Стр. 135 из 626
//
public void error(SAXParseException e)
throws SAXParseException
{
throw e;
}
//
public void warning(SAXParseException err)
throws SAXParseException
{
System.out.println("** Warning"
+ ", line " + err.getLineNumber()
+ ", uri " + err.getSystemId());
System.out.println(" " + err.getMessage());
}
Поскольку не существует нормального способа генерации сообщения без DTD или схемы,
вы пока еще ничего не сможете увидеть. Но как только это произойдет, вы уже будете
готовы!
&entityName;
Позже, при изучении DTD, вы узнаете, что можно определять свои собственные сущности,
так чтобы &yourEntityName; расширялся полностью в текст, определенный вами для этой
сущности. А сейчас мы рассмотрим предопределенные сущности и символьные ссылки,
не требующие какого-либо специального определения.
Web-
Rendered by www.RenderX.com
Стр. 136 из 626 Simple API for XML
Web-
Rendered by www.RenderX.com
Замена и вставка текста Стр. 137 из 626
<slide type="exec">
<title>Financial Forecast</title>
<item>Market Size < predicted</item>
<item>Anticipated Penetration</item>
<item>Expected Revenues</item>
<item>Profit Margin </item>
</slide>
</slideshow>
После выполнения программы Echo с вашим XML-файлом вы увидите следующую
информацию на экране:
ELEMENT: <item>
CHARS: Market Size < predicted
END_ELM: </item>
Анализатор преобразовал ссылку на сущность в ее значение и передал в приложение.
...
<slide type="tech">
<title>How it Works</title>
<item>First we fozzle the frobmorten</item>
<item>Then we framboze the staten</item>
<item>Finally, we frenzle the fuznaten</item>
<item><![CDATA[Diagram:
frobmorten <--------------- fuznaten
| <3> ^
| <1> | <1> = fozzle
Web-
Rendered by www.RenderX.com
Стр. 138 из 626 Simple API for XML
V | <2> = framboze
Staten--------------------+ <3> = frenzle
<2>
]]></item>
</slide>
</slideshow>
После выполнения программы Echo с новым файлом вы увидите следующую информацию
на экране:
ELEMENT: <item>
CHARS: Diagram:
frobmorten <--------------fuznaten
| <3> ^
| <1> | <1> = fozzle
V | <2> = framboze
staten----------------------+ <3> = frenzle
<2>
END_ELM: </item>
Вы можете заметить, что текст в секции CDATA пришел в том же виде, в каком он был
написан. Поскольку анализатор не рассматривал угловые скобки как символы XML, не
были сгенерированы фатальные ошибки, что произошло бы в противном случае. (Если
бы угловых скобок не было бы в секции CDATA, документ не был бы формально-
правильным.)
Web-
Rendered by www.RenderX.com
Создание определения типа документа (DTD) Стр. 139 из 626
<!--
DTD for a simple "slide show".
-->
Затем добавьте выделенный ниже текст для указания того, что элемент slideshow содержит
элементы slide и ничего более:
Web-
Rendered by www.RenderX.com
Стр. 140 из 626 Simple API for XML
Web-
Rendered by www.RenderX.com
Создание определения типа документа (DTD) Стр. 141 из 626
Web-
Rendered by www.RenderX.com
Стр. 142 из 626 Simple API for XML
<slideshow
Опять DTD-тег начинается с "<!". В данном случае имя тега, DOCTYPE, указывает, что
документом является slideshow. Это означает, что документ состоит из элемента slideshow
и всего остального внутри его:
<slideshow>
...
</slideshow>
Этот тег определяет элемент slideshow в качестве корневого элемента документа. XML-
документ должен иметь только один корневой элемент. Именно здесь указывается этот
элемент. Другими словами, этот тег идентифицирует содержимое документа как slideshow.
Тег DOCTYPE располагается после XML-определения и перед корневым элементом.
Идентификатор SYSTEM указывает расположение DTD-файла. Поскольку он не начинается
с префикса типа http:/ или file:/, путь к расположению XML-документа является
относительным. Вспомнили метод setDocumentLocator? Анализатор использует эту
информацию для поиска DTD-файла, так же как делало бы ваше приложение для поиска
файла относительно XML-документа. Мог бы использоваться также идентификатор PUBLIC
для указания того, что DTD-файл использует уникальное имя, но анализатор должен был
быть способен разрешить это имя.
Спецификация DOCTYPE могла бы, также, содержать DTD-определения внутри XML-
документа, а не обращаться к внешнему DTD-файлу. Такие определения должны
заключаться в квадратные скобки, например:
Web-
Rendered by www.RenderX.com
Влияние DTD на неверифицирующий анализатор Стр. 143 из 626
...
>
PROCESS: ...
CHARS:
ELEMENT: <slide
ATTR: ...
>
ELEMENT: <title>
CHARS: Wake up to ...
END_ELM: </title>
END_ELM: </slide>
CHARS:
ELEMENT: <slide
ATTR: ...
>
...
Сейчас вы увидите:
...
>
PROCESS: ...
ELEMENT: <slide
ATTR: ...
>
ELEMENT: <title>
CHARS: Wake up to ...
END_ELM: </title>
END_ELM: </slide>
ELEMENT: <slide
ATTR: ...
Web-
Rendered by www.RenderX.com
Стр. 144 из 626 Simple API for XML
>
...
Очевидно, что символы пробела, которые раньше выводились вокруг элементов slide,
больше не передаются анализатором, поскольку DTD объявляет, что slideshow состоит
только из элементов slide:
Web-
Rendered by www.RenderX.com
Влияние DTD на неверифицирующий анализатор Стр. 145 из 626
ELEMENT: <slideshow
ATTR: ...
>
IGNORABLE
IGNORABLE
PROCESS: ...
IGNORABLE
IGNORABLE
ELEMENT: <slide
ATTR: ...
>
IGNORABLE
ELEMENT: <title>
CHARS: Wake up to ...
END_ELM: </title>
IGNORABLE
END_ELM: </slide>
IGNORABLE
IGNORABLE
ELEMENT: <slide
ATTR: ...
>
...
Отсюда очевидно, что ignorableWhitespace вызывается перед и после комментариев и
элементов slide тогда, когда вызывался метод characters при отсутствии DTD.
7.8.2. Очистка
Теперь, когда вы увидели отображение игнорируемых пробелов, удалите этот код из вашей
версии программы Echo - для следующих упражнений он вам больше не нужен.
Примечание: Это изменение сделано в файле Echo09.java.
Web-
Rendered by www.RenderX.com
Стр. 146 из 626 Simple API for XML
<foo> </foo>
в котором существуют пробелы между тегами, а DTD определяет эти пробелы
игнорируемыми.
Web-
Rendered by www.RenderX.com
Определение атрибутов и сущностей в DTD Стр. 147 из 626
которых левая угловая скобка (>) никогда не будет истолкована как часть XML-тега. В
таблице 6-3 перечислены правильные варианты для типов атрибутов.
Таблица 6-3 Типы атрибутов
Тип атрибута Указывает…
(value1 | value2 | … ) Список значений, разделенных вертикальными линиями.
(Пример находится ниже).
CDATA "Неанализируемые символьные данные". (Для нормальных
людей - текстовая строка.)
ID Имя, которое не имеет ни один другой атрибут ID.
IDREF Ссылка на ID, определенный где-то в документе.
IDREFS Разделенный пробелами список, содержащий один или более
ID-ссылок.
ENTITY Имя сущности, определенной в DTD.
ENTITIES Разделенный пробелами список сущностей.
NMTOKEN Правильное XML-имя, состоящее из букв, цифр, дефисов,
знаков подчеркивания и двоеточий.
NMTOKENS Разделенный пробелами список имен.
NOTATION Название DTD-определенной нотации, описывающей формат
не XML-данных, таких как файлы изображений.*
Web-
Rendered by www.RenderX.com
Стр. 148 из 626 Simple API for XML
Спецификация Указывает…
"defaultValue" Значение по умолчанию, если значение не указано в
документе.
#FIXED "fixedValue" Значение для использования. Если документ указывает любое
значение, оно должно быть таким же.
<slideshow
title="WonderWidget&product; Slide Show"
...
Web-
Rendered by www.RenderX.com
Определение атрибутов и сущностей в DTD Стр. 149 из 626
<slide type="all">
<title>Wake up to WonderWidgets&products;!</title>
</slide>
ELEMENT: <title>
CHARS: Wake up to WonderWidgets!
END_ELM: </title>
Обратите внимание, что название продукта было замещено ссылкой на сущность.
Web-
Rendered by www.RenderX.com
Стр. 150 из 626 Simple API for XML
Добавьте выделенный ниже текст в предложение DOCTYPE вашего XML-файла для ссылки
на внешнюю сущность:
Web-
Rendered by www.RenderX.com
Обращение к двоичным сущностям Стр. 151 из 626
...
END_ELM: </slide>
ELEMENT: <slide
ATTR: type "all"
>
ELEMENT: <item>
CHARS:
This is the standard copyright message that our lawyers
make us put everywhere so we don't have to shell out a
million bucks every time someone spills hot coffee in their
lap...
END_ELM: </item>
END_ELM: </slide>
...
Обратите внимание, что новая строка, за которой следует комментарий, отображается как
символ, но сам комментарий проигнорирован. По этой причине сообщение об авторских
правах начинается с новой строки после метки CHARS: вместо того, чтобы идти сразу
после метки - первый отображаемый символ является символом новой строки, после
которого следует комментарий.
Web-
Rendered by www.RenderX.com
Стр. 152 из 626 Simple API for XML
Web-
Rendered by www.RenderX.com
Выбор вашей реализации анализатора Стр. 153 из 626
Однако это работать не будет. Прямой слеш не является частью установленного набора
символов для меток имени, поэтому такое объявление является ошибочным. Кроме того,
создание списка атрибутов в DTD ограничило бы доступные MIME-типы до определенных
на сегодняшний день. Использование же CDATA оставляет вопрос открытым, то есть
объявление будет продолжать оставаться правильным и при определении дополнительных
типов.
В документе ссылка на изображение с именем "intro-pic" может выглядеть примерно так:
Web-
Rendered by www.RenderX.com
Стр. 154 из 626 Simple API for XML
Web-
Rendered by www.RenderX.com
Использование верифицирующего анализатора Стр. 155 из 626
...
SAXParserFactory factory = SAXParserFactory.newInstance();
factory.setNamespaceAware(true);
factory.setValidating(true);
Более подробно о пространстве имен вы узнаете в разделе "Использование пространства
имен". Сейчас вы должны понимать, что верификация схемы - это ориентированный на
пространство имен процесс. Поскольку JAXP-совместимые анализаторы по умолчанию
не используют пространство имен, необходимо установить это свойство для работы
верификации схемы.
Последним действием является настройка анализатора на использование определенного
языка схемы. Для этого используются константы, определенные ранее для установки языка
W3C XML Schema:
saxParser.setProperty(JAXP_SCHEMA_LANGUAGE, W3C_XML_SCHEMA);
Во время работы необходимо, также, обрабатывать дополнительную ошибку. Рассмотрим
эту ошибку.
Web-
Rendered by www.RenderX.com
Стр. 156 из 626 Simple API for XML
Для обработки этой ситуации вы должны заключить оператор setProperty() в блок try/catch,
как показано в выделенном ниже коде.
...
SAXParser saxParser = factory.newSAXParser();
try {
saxParser.setProperty(JAXP_SCHEMA_LANGUAGE, W3C_XML_SCHEMA);
}
catch (SAXNotRecognizedException x) {
// ,
JAXP 1.2
...
}
...
<documentRoot
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation='YourSchemaDefinition.xsd'
>
...
Первый атрибут указывает префикс пространства имен XML (xmlns), "xsi", где "xsi"
обозначает "XML Schema Instance" ("Экземпляр XML-схемы"). Вторая строка указывает
используемую схему для элементов документа, которые не имеют префикса пространства
имен - то есть, для элементов, обычно определяемых вами в простых, не составных XML-
документах.
Примечание: Вы изучите пространство имен в разделе "Использование пространства
имен". А сейчас рассматривайте эти атрибуты как "магическую формулу", используемую
для верификации простого XML-файла, не использующего пространство имен. Как только
вы более близко познакомитесь с пространством имен, вы узнаете, как использовать XML
Schema для верификации сложных документов, использующих его. Эти вопросы
обсуждаются в разделе "Верификация при использовании нескольких пространств имен".
Web-
Rendered by www.RenderX.com
Использование верифицирующего анализатора Стр. 157 из 626
Можно, также, указать в приложении файл со схемой при помощи, например, следующего
кода:
...
SAXParser saxParser = spf.newSAXParser();
...
saxParser.setProperty(JAXP_SCHEMA_SOURCE,
new File(schemaSource));
Теперь, когда вы узнали, как использовать определение XML Schema, мы обратим ваше
внимание на типы ошибок, которые можно увидеть при верификации в приложении
входящих данных. Для этого будем использовать DTD.
Web-
Rendered by www.RenderX.com
Стр. 158 из 626 Simple API for XML
...
ELEMENT: <title>
CHARS: Overview
END_ELM: </title>
ELEMENT: <item>
CHARS: Why ** Parsing error, line 28, uri: ...
Element "em" must be declared.
org.xml.sax.SAXParseException: ...
...
Примечание: Приведенное выше сообщение генерируется библиотеками JAXP версии
1.2. Если вы используете другой анализатор, сообщение, возможно, будет другим.
Сообщение об ошибке указывает часть DTD, вызвавшую сбой при верификации. В данном
случае - это строка, определяющая элемент item как (#PCDATA | item).
Упражнение: Сделайте копию файла и удалите из него все теги <em>. Выполнится ли
верификация файла теперь? (В следующем разделе вы узнаете, как определить параметры
так, чтобы можно было использовать XHTML в элементах, которые мы определяем как
часть презентации слайдов.)
Web-
Rendered by www.RenderX.com
Определение сущностей-параметров и условных секций Стр. 159 из 626
Web-
Rendered by www.RenderX.com
Стр. 160 из 626 Simple API for XML
Web-
Rendered by www.RenderX.com
Определение сущностей-параметров и условных секций Стр. 161 из 626
Примечание: Modularized XHTML DTD определяет обе сущности - как inline, так и Inline, и
делает это немного по-разному. Вместо указания #PCDATA|em|b|a|img|Br ее определения
больше выглядят как (#PCDATA|em|b|a|img|Br)*. Использование одного из этих определений,
таким образом, больше выглядит как: <!ELEMENT title %Inline; >.
someExternal.dtd:
<![ INCLUDE [
... XML-only definitions
]]>
<![ IGNORE [
... SGML-only definitions
]]>
... common definitions
Условные секции начинаются с символов "<![", за которыми следует ключевое слово
INCLUDE или IGNORE и еще один символ "[". После этого идет содержимое условной
секции, заканчивающееся символами: "]]>". В данном случае XML-определения включены,
а SGML-определения исключены. Это хорошо для XML-документов, но вы не сможете
использовать DTD для SGML-документов. Вы, конечно, можете изменить ключевые слова,
но это только поменяет проблему.
Решением является использование ссылок на параметры-сущности вместо ключевых слов
INCLUDE и IGNORE:
someExternal.dtd:
<![ %XML; [
... XML-only definitions
]]>
<![ %SGML; [
... SGML-only definitions
]]>
... common definitions
Теперь каждый документ, использующий DTD, может установить определения
соответствующей сущности:
Web-
Rendered by www.RenderX.com
Стр. 162 из 626 Simple API for XML
Web-
Rendered by www.RenderX.com
Анализ параметризованного DTD Стр. 163 из 626
...
<slide type="all">
<slide-title>Wake up to ... </slide-title>
</slide>
...
7.14.1. DTD-предупреждения
Как упоминалось ранее в этом руководстве, предупреждения генерируются только во
время обработки SAX-анализатором DTD. Некоторые предупреждения генерируются
Web-
Rendered by www.RenderX.com
Стр. 164 из 626 Simple API for XML
Web-
Rendered by www.RenderX.com
Обработка лексических событий Стр. 165 из 626
В этом разделе руководства даются ответы на эти вопросы. Здесь показано, как
использовать org.xml.sax.ext.LexicalHandler для идентификации комментариев, секций
CDATA и ссылок на анализируемые сущности.
Комментарии, секции CDATA и ссылки на анализируемые сущности составляют лексическую
информацию, то есть, информацию, относящуюся собственно к тексту XML, а не к
содержимому XML. Большинство приложений, конечно, имеют дело только с содержимым
XML-документа. Такие приложения не будут использовать LexicalEventListener API. Но
приложения, выводящие XML-текст, найдут этот API бесценным.
Примечание: Обработка лексических событий является необязательной возможностью
анализатора. От реализации анализатора не требуется ее поддержки. (Данная реализация
поддерживает ее.) Это обсуждение полагает, что ваш анализатор поддерживает обработку
лексических событий.
comment(String comment)
Передает комментарии в приложение.
startCDATA(), endCDATA()
Указывает, когда секция CDATA начинается и заканчивается. При этом ваше приложение
будет знать, какой тип символов ожидается при следующем вызове characters().
import org.xml.sax.*;
Web-
Rendered by www.RenderX.com
Стр. 166 из 626 Simple API for XML
import org.xml.sax.helpers.DefaultHandler;
import org.xml.sax.ext.LexicalHandler;
...
public class Echo extends HandlerBase
implements LexicalHandler
{
public static void main(String argv[])
{
...
//
SAX-
DefaultHandler handler = new Echo();
Echo handler = new Echo();
...
С этого момента класс Echo расширяет один класс и реализует дополнительный интерфейс.
Соответственно, вы изменили и класс переменной-обработчика, так что можете
использовать один и тот же экземпляр, как DefaultHandler, так и LexicalHandler.
Далее, добавьте выделенный ниже код для получения XMLReader, к которому обращается
анализатор, и для настройки его на передачу лексических событий в ваш обработчик:
Web-
Rendered by www.RenderX.com
Обработка лексических событий Стр. 167 из 626
Web-
Rendered by www.RenderX.com
Стр. 168 из 626 Simple API for XML
Web-
Rendered by www.RenderX.com
Обработка лексических событий Стр. 169 из 626
Web-
Rendered by www.RenderX.com
Стр. 170 из 626 Simple API for XML
systemId)
throws SAXException
{
nl();
emit("START DTD: "+name
+" publicId=" + publicId
+" systemId=" + systemId);
}
Web-
Rendered by www.RenderX.com
Использование DTDHandler и EntityResolver Стр. 171 из 626
frobmorten <--------------fuznaten
| <3> ^
| <1> | <1> = fozzle
V | <2> = framboze
staten----------------------+ <3> = frenzle
<2>
Web-
Rendered by www.RenderX.com
Стр. 172 из 626 Simple API for XML
Web-
Rendered by www.RenderX.com
Дополнительная информация Стр. 173 из 626
доступа к локальной копии, если таковая существует, вы должны где-то в системе создать
каталог, который отобразит имена (общедоступные ID) в локальные URL.
Web-
Rendered by www.RenderX.com
Стр. 174 из 626 Document Object Model
1.2 поддерживает стандарт XML Schema, который может быть важным для любого
приложения.
С другой стороны, если вы имеете дело с простыми структурами данных, и XML Schema
не играет большой роли в ваших планах, то вы, возможно, найдете, что один из более
объектно-ориентированных стандартов, таких как JDOM и dom4j, больше подходит для
ваших целей.
С самого начала DOM разрабатывался нейтральным к языку. Поскольку он был
предназначался для использования с языками, подобными С или Perl, DOM не использует
преимуществ объектно-ориентированных особенностей Java. Этот факт, в дополнение к
различиям документ/данные, также помогает объяснить различия в обработке структур
DOM и JDOM или dom4j.
В этом разделе мы исследуем различия между моделями, лежащими в основе этих
стандартов, что поможет вам выбрать тот, который наиболее подходит для вашего
приложения.
Иерархия DOM-узлов будет выглядеть примерно так (каждая строка представляет один
узел):
ELEMENT: sentence
+ TEXT: This is an
+ ELEMENT: bold
Web-
Rendered by www.RenderX.com
Когда используется DOM Стр. 175 из 626
+ TEXT: important
+ TEXT: idea.
Обратите внимание, что элемент sentence содержит текст, за которым следует субэлемент
и далее дополнительный текст. Это и есть то смешение текста и элементов, которое и
определяет "модель со смешанным содержимым"
<addressbook>
<entry>
<name>Fred</name>
Web-
Rendered by www.RenderX.com
Стр. 176 из 626 Document Object Model
<email>fred@home</email>
</entry>
...
</addressbook>
Примечание: Для очень простых XML-структур, таких как эта, вы можете также использовать
пакет регулярных выражений (java.util.regex), встроенный в версию 1.4 платформы Java.
В JDOM и dom4j после перемещения к элементу, содержащему текст, для получения его
содержимого вызывается метод text(). В DOM вы должны проверить список субэлементов
для составления текста узла, даже если, как вы уже видели, этот список содержит только
один элемент (узел TEXT).
Таким образом, для таких простых структур данных как приведенная выше адресная книга
вы можете сохранить ваше время, используя JDOM или dom4j. Также имеет смысл
использовать одну из этих моделей даже при технически "смешанных" данных, но если
всегда существует один (и только один) сегмент текста для конкретного узла.
Вот пример структуры такого типа, которая могла бы легко обрабатываться в JDOM или
dom4j:
<addressbook>
<entry>Fred
<email>fred@home</email>
</entry>
...
</addressbook>
Здесь каждая запись содержит небольшой текст, за которым следуют другие элементы.
С этой структурой программа могла бы переместиться к записи, вызвать text() для
определения адресата и обработать субэлемент <email> нужного узла.
Web-
Rendered by www.RenderX.com
Когда используется DOM Стр. 177 из 626
Вот DOM-структура этих данных. Она четко представляет тип структуры, к обработке
которой должно быть готово приложение:
+ ELEMENT: sentence
+ TEXT: The
+ ENTITY REF: projectName
+ COMMENT: The latest name we're using
+ TEXT: Eagle
+ CDATA: <i>project</i>
+ TEXT: is
+ PI: editor: red
+ ELEMENT: bold
+ TEXT: important
+ PI: editor: normal
Этот пример показывает типы узлов, которые могут встретиться в DOM. Хотя ваше
приложение может в большинстве случаев игнорировать большинство из них, по-
настоящему устойчивое приложение должно распознавать и обрабатывать каждый тип
узла.
Подобным же образом процесс перемещения к узлу включает в себя обработку
субэлементов, то есть, игнорирование ненужных и проверку требуемых до тех пор, пока
не будет найден искомый узел.
Часто в таких случаях необходимо найти узел, содержащий конкретный текст. Например,
в разделе "DOM API" вы искали узел <coffee>, элемент <name> которого содержал текст
"Mocha Java". Для такого поиска программе необходимо было работать со списком
элементов <coffee> и для каждого элемента: а) получить элемент <name>; б) проверить
узел TEXT этого элемента.
Однако в этом примере были сделаны некоторые упрощения. Предполагалось, что в
структуре данных не могло содержаться инструкций обработки, комментариев, узлов
CDATA и ссылок на сущности. Многие простые приложения могут тоже делать такие
предположения. Но по-настоящему устойчивые приложения должны быть готовы иметь
дело со всеми типами XML-данных.
("Простое" приложение будет работать только в тех случаях, когда входные данные
содержат ожидаемые им упрощенные XML-структуры. Нет механизмов проверки того, что
не будут существовать более сложные структуры. В конце концов, XML создавался
специально для таких структур.)
Для более устойчивой работы код примера, описанного в разделе "DOM API", должен
выполнить следующее:
1. При поиске элемента <name>:
2.
A. Игнорировать комментарии, атрибуты и инструкции обработки.
B. Учитывать возможность того, что субэлементы <coffee> могут встречаться в разном
порядке.
Web-
Rendered by www.RenderX.com
Стр. 178 из 626 Document Object Model
Web-
Rendered by www.RenderX.com
Чтение XML-данных в DOM Стр. 179 из 626
Web-
Rendered by www.RenderX.com
Стр. 180 из 626 Document Object Model
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.FactoryConfigurationError;
import javax.xml.parsers.ParserConfigurationException;
Добавьте следующие строки для возможных исключительных ситуаций, генерируемых
при анализе XML-документа:
import org.xml.sax.SAXException;
import org.xml.sax.SAXParseException;
Добавьте эти строки для чтения XML-файла и идентификации ошибок:
import java.io.File;
import java.io.IOException;
Наконец, импортируйте W3C-определение для DOM и исключительных ситуаций DOM:
import org.w3c.dom.Document;
import org.w3c.dom.DOMException;
Примечание: DOMException генерируется только при обходе или управлении DOM. Ошибки,
возникающие при анализе, используют другой механизм вывода, объясняемый ниже.
Web-
Rendered by www.RenderX.com
Чтение XML-данных в DOM Стр. 181 из 626
try {
//
Exception x = spe;
if (spe.getException() != null)
x = spe.getException();
x.printStackTrace();
pce.printStackTrace();
Web-
Rendered by www.RenderX.com
Стр. 182 из 626 Document Object Model
}// main
try {
DocumentBuilder builder = factory.newDocumentBuilder();
document = builder.parse( new File(argv[0]) );
} catch (SAXParseException spe) {
Сохраните этот файл!
Сейчас вы, возможно, подумали о том, что каждое JAXP-приложение начинается примерно
одинаково. Вы правы! Сохраните эту версию файла в виде шаблона. Вы будете
использовать этот шаблон в дальнейшем как основу приложения XSLT-преобразований.
Web-
Rendered by www.RenderX.com
Чтение XML-данных в DOM Стр. 183 из 626
Web-
Rendered by www.RenderX.com
Стр. 184 из 626 Document Object Model
builder.setErrorHandler(
new org.xml.sax.ErrorHandler() {
//
( )
public void fatalError(SAXParseException exception)
throws SAXException {
}
//
//
public void warning(SAXParseException err)
throws SAXParseException
{
System.out.println("** Warning"
+ ", line " + err.getLineNumber()
+ ", uri " + err.getSystemId());
System.out.println(" " + err.getMessage());
}
);
Этот код использует анонимный класс для генерации экземпляра объекта, реализующего
интерфейс ErrorHandler. Поскольку он не имеет имени класса, он является "анонимным".
Вы можете рассматривать его как экземпляр "ErrorHandler", хотя технически он является
не имеющим имени экземпляром, реализующим указанный интерфейс. Код в большей
части такой же, как и описанный в разделе "Обработка ошибок неверифицирующим
анализатором". Более подробная информация по вопросам верификации находится в
разделе "Использование верифицирующего анализатора".
Web-
Rendered by www.RenderX.com
Отображение DOM-иерархии Стр. 185 из 626
// GUI
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTree;
Затем мы модифицируем программу для генерации дружественного пользователю
отображения JTree. При выборе пользователем элемента в дереве вы отобразите
субэлементы в смежной панели. Поскольку мы сейчас делаем подготовительную работу,
импортируйте компоненты для разделения области просмотра (JSplitPane) и отображения
текста субэлементов (JEditorPane):
import javax.swing.JSplitPane;
import javax.swing.JEditorPane;
Web-
Rendered by www.RenderX.com
Стр. 186 из 626 Document Object Model
// GUI
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.Toolkit;
import java.awt.event.WindowEvent;
import java.awt.event.WindowAdapter;
И, наконец, импортируйте некоторые классы для создания рамки:
//
import javax.swing.border.EmptyBorder;
import javax.swing.border.BevelBorder;
import javax.swing.border.CompoundBorder;
(Они не обязательны. Вы можете, если хотите, для упрощения пропустить их и код, их
использующий.)
Web-
Rendered by www.RenderX.com
Отображение DOM-иерархии Стр. 187 из 626
...
} // main
// ,
Web-
Rendered by www.RenderX.com
Стр. 188 из 626 Document Object Model
frame.setLocation(screenSize.width/3 - w/2,
screenSize.height/2 - h/2);
frame.setSize(w, h);
frame.setVisible(true)
} // makeFrame
public DomEcho02()
{
} //
Используйте импортированные ранее классы для создания красивой рамки (необязательно):
public DomEcho02()
{
//
EmptyBorder eb = new EmptyBorder(5,5,5,5);
BevelBorder bb = new BevelBorder(BevelBorder.LOWERED);
CompoundBorder cb = new CompoundBorder(eb,bb);
this.setBorder(new CompoundBorder(cb,eb));
} //
Затем, создайте пустое дерево и разместите его в JScrollPane, чтобы пользователь видел
его содержимое по мере его роста:
public DomEcho02(
{
...
//
JTree tree = new JTree();
Web-
Rendered by www.RenderX.com
Отображение DOM-иерархии Стр. 189 из 626
//
JScrollPane treeView = new JScrollPane(tree);
treeView.setPreferredSize(
new Dimension( leftWidth, windowHeight ));
} //
Теперь создайте нередактируемую JEditPane, в которой будет отображаться содержимое
выбранных узлов JTree:
public DomEcho02(
{
....
//
JEditorPane htmlPane = new JEditorPane("text/html","");
htmlPane.setEditable(false);
JScrollPane htmlView = new JScrollPane(htmlPane);
htmlView.setPreferredSize(
new Dimension( rightWidth, windowHeight ));
} //
Для хранения построенных JTree и JEditorPane создайте JSplitPane:
public DomEcho02()
{
....
//
JSplitPane splitPane =
new JSplitPane(JSplitPane.HORIZONTAL_SPLIT,
treeView, htmlView );
splitPane.setContinuousLayout( true );
splitPane.setDividerLocation( leftWidth );
splitPane.setPreferredSize(
new Dimension( windowWidth + 10, windowHeight+10 ));
} //
Web-
Rendered by www.RenderX.com
Стр. 190 из 626 Document Object Model
public DomEcho02()
{
...
// GUI-
this.setLayout(new BorderLayout());
this.add("Center", splitPane );
} //
Поздравляем! Программа стала GUI-приложением. Вы можете выполнить ее сейчас, чтобы
посмотреть ее общий вид на экране. Для справки, вот полный конструктор:
public DomEcho02()
{
//
EmptyBorder eb = new EmptyBorder(5,5,5,5);
BevelBorder bb = new BevelBorder(BevelBorder.LOWERED);
CompoundBorder CB = new CompoundBorder(eb,bb);
this.setBorder(new CompoundBorder(CB,eb));
//
JTree tree = new JTree();
//
JScrollPane treeView = new JScrollPane(tree);
treeView.setPreferredSize(
new Dimension( leftWidth, windowHeight ));
//
JEditorPane htmlPane = new JEditorPane("text/html","");
htmlPane.setEditable(false);
JScrollPane htmlView = new JScrollPane(htmlPane);
htmlView.setPreferredSize(
new Dimension( rightWidth, windowHeight ));
Web-
Rendered by www.RenderX.com
Отображение DOM-иерархии Стр. 191 из 626
//
JSplitPane splitPane =
new JSplitPane(JSplitPane.HORIZONTAL_SPLIT,
treeView, htmlView )
splitPane.setContinuousLayout( true );
splitPane.setDividerLocation( leftWidth );
splitPane.setPreferredSize(
new Dimension( windowWidth + 10, windowHeight+10 ));
// GUI-
this.setLayout(new BorderLayout());
this.add("Center", splitPane );
} //
// TreeModel
import javax.swing.tree.*;
import javax.swing.event.*;
import java.util.*;
Web-
Rendered by www.RenderX.com
Стр. 192 из 626 Document Object Model
Переместившись в конец программы, определите набор строк для типов узловых элементов:
...
} // makeFrame
// DOM-
// ( = nodeType().)
static final String[] typeName = {
"none",
"Element",
"Attr",
"Text",
"CDATA",
"EntityRef",
"Entity",
"ProcInstr",
"Comment",
"Document",
"DocType",
"DocFragment",
"Notation",
};
} // DomEcho
Это строки, отображаемые в JTree. Спецификация этих типов узлов находится в Document
Object Model (DOM) Level 2 Core Specification в http://www.w3.org/TR/2000/REC_DOM/Level-
2-Core-20001113. Ниже приведена эта таблица с измененными для ясности заголовками
и с добавленным столбцом nodeType():
Таблица 1 Типы узлов
Узел nodeName() nodeValue() attributes nodeType()
Attr имя атртибута значение атрибута null 2
CDATASection #cdata-section содержимое CDATASec- null 4
tion
Comment #comment содержимое null 8
комментария
Document #document null null 9
DocumentFragment #document-fragment null null 11
DocumentType название типа null null 10
документа
Element имя тега null NamedNodeMap 1
Entity имя сущности null null 6
EntityReference имя ссылаемой null null 5
сущности
Web-
Rendered by www.RenderX.com
Отображение DOM-иерархии Стр. 193 из 626
Предложения:
Распечатайте эту таблицу и держите ее под рукой. Вам она понадобится при работе с
DOM, поскольку все эти типы смешаны в DOM-дереве. То есть, ваш код постоянно
спрашивает: "Это ли тип узла, который меня интересует?".
Теперь определим AdapterNode, оболочку для DOM-узлов, как внутренний класс:
// AdapterNode DOM-
public AdapterNode(org.w3c.dom.Node node) {
domNode = node;
}
// ,
//
public String toString() {
String s = typeName[domNode.getNodeType()];
String nodeName = domNode.getNodeName();
if (! nodeName.startsWith("#")) {
s += ": " + nodeName;
}
if (domNode.getNodeValue() != null) {
if (s.startsWith("ProcInstr"))
s += ", ";
else
s += ": ";
Web-
Rendered by www.RenderX.com
Стр. 194 из 626 Document Object Model
//
//
String t = domNode.getNodeValue().trim();
int x = t.indexOf(");
if (x >= 0) t = t.substring(0, x);
s += t;
}
return s;
}
} // AdapterNode
} // DomEcho
Этот класс объявляет переменную для хранения DOM-узла и требует указания его в
аргументе конструктора. Затем он определяет операцию toString, которая возвращает тип
узла из массива String, и добавляет к нему дополнительную информацию из узла для
дальнейшей его идентификации.
Как видно из таблицы типов узлов в org.w3c.dom.Node, каждый узел имеет тип, имя и
значение, которые могут быть пустыми. В тех случаях, когда имя узла начинается с "#",
это поле дублирует тип узла, поэтому нет смысла включать его. Это объясняет присутствие
строк:
if (! nodeName.startsWith("#")) {
s += ": " + nodeName;
}
Оставшаяся часть метода toString также заслуживает некоторого внимания. Например,
следующие строки:
if (s.startsWith("ProcInstr"))
s += ", ";
else
s += ": ";
просто обеспечивают немного "синтаксических украшений". Поле типа для инструкций
обработки заканчивается двоеточием (:), поэтому эти строки предотвращают дублирование
двоеточий.
Другими интересными строчками являются:
String t = domNode.getNodeValue().trim();
int x = t.indexOf(");
Web-
Rendered by www.RenderX.com
Отображение DOM-иерархии Стр. 195 из 626
Web-
Rendered by www.RenderX.com
Стр. 196 из 626 Document Object Model
} // AdapterNode
} // DomEcho
Примечание: Во время разработки только после написания адаптера TreeModel я понял,
что это необходимо, и добавил этот код. Через некоторое время вы увидите, почему.
...
} // AdapterNode
// Document
(DOM)
// JTree.
public class DomToTreeModelAdapter implements
javax.swing.tree.TreeModel
{
// TreeModel
public Object getRoot() {
//System.err.println("Returning root: " +document);
return new AdapterNode(document);
}
Web-
Rendered by www.RenderX.com
Отображение DOM-иерархии Стр. 197 из 626
// , .
// true ,
// TreeNodesChanged.
}
} // DomToTreeModelAdapter
} // DomEcho
Web-
Rendered by www.RenderX.com
Стр. 198 из 626 Document Object Model
В этом коде метод getRoot возвращает корневой узел DOM, оформленный как объект
AdapterNode. После этого все узлы, возвращаемые адаптером, будут иметь тип
AdapterNodes, который включает в себя DOM-узлы. По этому признаку, когда бы мы ни
спросили JTree о потомках данного узла, о количестве потомков и т.д., JTree будет
передавать нам AdapterNode. Мы знаем это, поскольку контролируем каждый узел в JTree,
начиная с корневого узла.
JTree использует метод isLeaf для определения необходимости отобразить иконку
открытия/закрытия слева от узла. Этот метод возвращает true только если узел не имеет
потомков. Здесь мы выполняем преобразование типа оригинального объекта JTree в объект
AdapterNode, каким он и должен быть. Мы знаем, что передается объект адаптера, но
интерфейс, вообще говоря, определяет объекты, поэтому мы должны выполнить
преобразование.
Следующие три метода возвращают количество потомков указанного узла, потомка,
имеющего заданный индекс, и индекс указанного потомка соответственно. Это все
достаточно просто.
Последний метод вызывается тогда, когда пользователь меняет значение, сохраненное
в JTree. В этом приложении мы не будем поддерживать это. Но если бы мы включили
такую возможность, приложение должно было бы сделать изменение в модели и затем
проинформировать какой-либо перехватчик событий об этом изменении. (JTree может
быть не единственным перехватчиком. Во многих приложениях это в действительности
так.)
Для информирования перехватчиков событий об изменении, необходимо зарегистрировать
их. Это ведет нас к рассмотрению последних двух методов для реализации в интерфейсе
TreeModel. Добавьте выделенный ниже код для их определения:
Web-
Rendered by www.RenderX.com
Отображение DOM-иерархии Стр. 199 из 626
TreeModelListener listener )
{
if ( listener != null ) {
listenerList.removeElement( listener );
}
}
} // DomToTreeModelAdapter
Поскольку приложение не будет делать изменений в дереве, эти методы пока не будут
использоваться. Однако вы можете использовать их в будущем при необходимости.
Примечание: Этот пример использует Vector, так что будет работать с приложениями
версии 1.1. Если работать с версиями 1.2 или более поздними, я бы использовал вместо
них отличную коллекцию: private LinkedList listenerList=new LinkedList();
Операциями над List являются add и remove. Для прохода по списку можно использовать
следующие операции:
Iterator it = listenerList.iterator();
while ( it.hasNext() ) {
TreeModelListener listener = (TreeModelListener) it.next();
...
}
Приведем, также, несколько необязательных методов, которые вы не будете использовать
в этом приложении. К этому времени вы построили работающий шаблон для адаптера
TreeModel. В интересах полноты вы, возможно, захотите добавить выделенный ниже код.
Вы можете затем вызывать его всегда, когда необходимо будет проинформировать
перехватчики JTree об изменениях:
Web-
Rendered by www.RenderX.com
Стр. 200 из 626 Document Object Model
} // DomToTreeModelAdapter
Примечание: Эти методы взяты из класса TreeModelSupport, описанного в статье "Under-
standong the TreeModel". Эта архитектура разработана Tom Santos и Steve Wilson, и является
намного более элегантной, чем описанная здесь. Поэтому стоит поместить эти методы
сюда, чтобы они были всегда под рукой, когда возникнет необходимость.
8.3.4. Завершение
К данному моменту вы в основном сделали все. Все что вам нужно - возвратиться назад
к конструктору и добавить код для построения адаптера и передачи его в JTree как
TreeModel:
//
JTree tree = new JTree(new DomToTreeModelAdapter());
Web-
Rendered by www.RenderX.com
Исследование структуры DOM Стр. 201 из 626
Вспомните, что первой частью отображаемого текста для каждого узла является тип
элемента. Затем идет имя элемента, если оно есть, и его значение. Для узла Comment
отображается атрибут value, тогда как для узла Element отображается атрибут name -
"slideshow".
Сравните рисунок 1 с кодом в методе AdapterNode toString, чтобы увидеть, имя или значение
отображается для конкретного узла. Если вы хотите сделать выводимую информацию
более понятной, можно указывать отображаемое свойство (например, N: name, V: value).
При расширении элемента slideshow отобразится информация, показанная на рисунке 2.
Web-
Rendered by www.RenderX.com
Стр. 202 из 626 Document Object Model
Здесь вы можете увидеть узлы Text и Comment, разбросанные между элементами Slide.
Пустые узлы Text появляются потому, что нет DTD для информирования анализатора об
отсутствии текста. (Вообще говоря, подавляющим большинством узлов DOM-дерева будут
узлы Element и Text.)
Это важно!
Текстовые узлы существуют в DOM под узлами элементов, а данные всегда хранятся в
текстовых узлах. Возможно, наиболее общая ошибка при обработке DOM является
перемещение на узел элемента и ожидание того, что он содержит хранимые в нем данные.
Это не так! Даже самый простой узел элемента имеет свой текстовый узел. Например, в
<size>12</size> имеется узел элемента (size) и текстовый узел в нем, содержащий
фактические данные (12).
На этом рисунке совершенно отсутствуют узлы Attribute. Из таблицы org.w3c.dom.Node
видно, что существует тип узла Attribute. Но они не включены как потомки в иерархию DOM.
Доступ к ним можно получить при помощи вызова метода getAttributes интерфейса Node.
Примечание: Отображение текстовых узлов является причиной включения приведенных
ниже строк кода в методе toString AdapterNode. Если вы удалите их, вы увидите непонятные
символы (обычно квадратики), генерируемые символами новой строки, находящимися в
тексте.
String t = domNode.getNodeValue().trim();
int x = t.indexOf(");
if (x >= 0) t = t.substring(0, x);
s += t;
Web-
Rendered by www.RenderX.com
Исследование структуры DOM Стр. 203 из 626
Web-
Rendered by www.RenderX.com
Стр. 204 из 626 Document Object Model
Вы можете заметить, что в DOM был вставлен текстовый узел, содержащий информацию
об авторских правах, а не ссылка на сущность, указывающая на нее.
Для большинства приложений вставка текста - это именно то что вам нужно. При этом во
время просмотра текста узла вам не нужно беспокоиться о ссылках на сущность, которые
он может содержать.
Для других приложений, однако, вам может понадобиться способность восстанавливать
оригинальный XML. Например, редактор должен сохранять результаты пользовательских
изменений без замены ссылок на сущность.
Различные DocumentBuilderFactory API дают вам контроль над типом создаваемой DOM-
структуры. Например, добавьте выделенный ниже код для создания DOM-структуры,
показанной на рисунке 6.
Web-
Rendered by www.RenderX.com
Исследование структуры DOM Стр. 205 из 626
Здесь выделен узел ссылки на сущность. Обратите внимание, что ссылка на сущность
содержит несколько узлов. Этот пример показывает только узлы комментариев и текстовые
узлы, но сущность может потенциально содержать также другие узлы элементов.
Наконец, при перемещении вниз к последнему элементу item в последнем slide отобразится
информация, показанная на рисунке 7.
Здесь выделен узел CDATA. Обратите внимание, что он не содержит узлов. Поскольку
секция CDATA полностью неинтерпретируемая, все ее содержимое содержится в свойстве
value.
Web-
Rendered by www.RenderX.com
Стр. 206 из 626 Document Object Model
8.4.3. Завершение
Вы увидели большинство узлов, которые можно встретить в дереве DOM. Существует
еще один или два, которые мы обсудим в следующем разделе, но вы уже знаете все, что
вам необходимо для создания или изменения DOM-структуры. В следующем разделе вы
узнаете, как преобразовать DOM в подходящий для интерактивного GUI объект JTree.
Или, если вы хотите, можете пропустить следующие разделы до 5-ой главы руководства
по DOM "Создание и управление DOM", где вы научитесь создавать DOM с нуля.
Web-
Rendered by www.RenderX.com
Создание дружественного пользователю JTree из DOM Стр. 207 из 626
...
import org.w3c.dom.Document;
import org.w3c.dom.DOMException;
import org.w3c.dom.Node;
Web-
Rendered by www.RenderX.com
Стр. 208 из 626 Document Object Model
// DOM
static final String[] typeName = {
...
};
//
Web-
Rendered by www.RenderX.com
Создание дружественного пользователю JTree из DOM Стр. 209 из 626
Web-
Rendered by www.RenderX.com
Стр. 210 из 626 Document Object Model
Web-
Rendered by www.RenderX.com
Создание дружественного пользователю JTree из DOM Стр. 211 из 626
break;
}
}
}
return new AdapterNode(node);
} //
} // AdapterNode
Здесь нет ничего особенного. Это немного измененная версия той же логики, которую вы
использовали для возврата количества потомков.
Web-
Rendered by www.RenderX.com
Стр. 212 из 626 Document Object Model
Web-
Rendered by www.RenderX.com
Создание дружественного пользователю JTree из DOM Стр. 213 из 626
s += adpNode.content();
Web-
Rendered by www.RenderX.com
Стр. 214 из 626 Document Object Model
Web-
Rendered by www.RenderX.com
Создание дружественного пользователю JTree из DOM Стр. 215 из 626
Так же как и для текстового узла, вы возвращаете value узла. Однако, поскольку текст в
данном случае может содержать угловые скобки и амперсанды, вы должны преобразовать
их в форму, правильно отображающую их в HTML-области. В отличие от тега XML CDATA
тег HTML <pre> не гарантирует отсутствие анализа тегов форматирования, разделителей
и т.д. Поэтому вы должны преобразовать левые угловые скобки (<) и амперсанды (&) для
их корректного отображения.
С другой стороны, существует небольшое количество типов, которые вы не обрабатываете
в вышеприведенном коде. Стоит потратить немного времени на их рассмотрение, чтобы
понять почему:
Attribute
Эти узлы не появляются в DOM, а возвращаются при вызове getAttribute узлов элемента.
Entity
Эти узлы тоже не появляются в DOM, а возвращаются при вызове getEntities узлов DocType.
Processing Instruction
Эти узлы не содержат отображаемых данных.
Comment
То же самое. Ничего нет, чтобы вы хотели отображать.
Document
Это корневой элемент DOM. Нет данных для отображения.
DocType
Узел DocType содержит спецификацию DTD с внешними указателями, или без них. Он
появляется только в корневом узле и не имеет данных для отображения в дереве.
Document Fragment
Этот узел эквивалентен узлу Document. Это - корневой элемент, который спецификация
DOM использует для хранения промежуточных результатов, например, при операциях
вырезания/вставки. Подобно узлу Document не содержит отображаемых данных.
Notation
Мы игнорируем этот узел. Он предназначен для включения двоичных данных в DOM. Как
обсуждалось ранее в разделах "Ссылка на двоичные сущности" и "Использование
DTDHandler и EntityResolver" типы MIME (вместе с пространствами имен) предлагают
лучший механизм для этого.
Web-
Rendered by www.RenderX.com
Стр. 216 из 626 Document Object Model
tree.addTreeSelectionListener(
new TreeSelectionListener() {
public void valueChanged(TreeSelectionEvent e)
Web-
Rendered by www.RenderX.com
Создание дружественного пользователю JTree из DOM Стр. 217 из 626
{
TreePath p = e.getNewLeadSelectionPath();
if (p != null) {
AdapterNode adpNode =
(AdapterNode)
p.getLastPathComponent();
htmlPane.setText(adpNode.content());
}
}
}
);
Теперь при выборе узла JTree его содержимое передается в htmlPane.
Примечание: TreeSelectionListener в этом примере создается при помощи анонимного
внутреннего класса адаптера. При программировании для платформы версии 1.1
необходимо использовать внешний класс.
При компиляции этой версии приложения вы сразу обнаружите, что htmlPane должна быть
указана как final для ссылки во внутреннем классе, поэтому добавьте выделенное ниже
ключевое слово:
public DomEcho04()
{
...
//
final JEditorPane htmlPane = new
JEditorPane("text/html","");
htmlPane.setEditable(false);
JScrollPane htmlView = new JScrollPane(htmlPane);
htmlView.setPreferredSize(
new Dimension( rightWidth, windowHeight ));
Web-
Rendered by www.RenderX.com
Стр. 218 из 626 Document Object Model
Web-
Rendered by www.RenderX.com
Создание дружественного пользователю JTree из DOM Стр. 219 из 626
Web-
Rendered by www.RenderX.com
Стр. 220 из 626 Document Object Model
8.5.4. Завершение
Теперь вы понимаете достаточно много в структуре DOM и знаете, как адаптировать DOM
для создания дружественного пользователю приложения. Это потребовало немного
кодирования, но в результате вы получили ценное средство для отображения структуры
DOM и шаблон GUI-приложения. В следующем разделе вы сделаете несколько изменений
в коде, которые превратят приложение в средство для экспериментов, а затем
поэкспериментируете с созданием и управлением DOM.
Web-
Rendered by www.RenderX.com
Создание и управление DOM Стр. 221 из 626
main для создания buildDom. Показанные ниже изменения необходимы, чтобы настроить
этот код для метода buildDom.
pce.printStackTrace();
} catch (IOException ioe) {
...
}
}
В этом коде вы заменили строку, делающую анализ, строкой, создающей DOM. Затем,
поскольку код больше не анализирует существующий файл, вы удалили исключительные
ситуации, которые больше не генерируются: SAXException и IOException.
И поскольку вы собираетесь работать с объектами Element, добавьте операторы импорта
этого класса в начало программы:
import org.w3c.dom.Document;
import org.w3c.dom.DOMException;
import org.w3c.dom.Element;
Web-
Rendered by www.RenderX.com
Стр. 222 из 626 Document Object Model
pce.printStackTrace();
}
}
Наконец, измените код проверки списка аргументов в начале метода main для вызова
buildDom и makeFrame вместо генерирования ошибки, как показано ниже:
Web-
Rendered by www.RenderX.com
Создание и управление DOM Стр. 223 из 626
makeFrame();
return;
}
Пока это все! Теперь, если вы укажете аргумент, этот файл будет анализироваться, если
нет - будет выполняться экспериментальный код, строящий DOM.
Web-
Rendered by www.RenderX.com
Стр. 224 из 626 Document Object Model
Здесь вы можете заметить, что смежные текстовые узлы были соединены в один узел.
Операция нормализации является одной из операций, которую вы обычно будете
использовать после проведения изменений в DOM, чтобы гарантировать как можно большую
компактность результата.
Примечание: Теперь, когда у вас есть программа для экспериментов, посмотрите, что
произойдет с другими комбинациями узлов CDATA, ссылок на сущности и текстовых узлов
при нормализации дерева.
Web-
Rendered by www.RenderX.com
Создание и управление DOM Стр. 225 из 626
/**
* .
* <li>
.
* <li> TEXT (
* ,
.
* <li> CDATA EntityRef.
* <li>
.
* </ul>
* @param name
* @param node ,
* @return
*/
public Node findSubNode(String name, Node node) {
if (node.getNodeType() != Node.ELEMENT_NODE) {
System.err.println("Error: Search node not of element
type");
System.exit(22);
}
Web-
Rendered by www.RenderX.com
Стр. 226 из 626 Document Object Model
/**
* , .
:<ul>
* <li>
.
* <li> TEXT, CDATA,
* EntityRef.
* <li>
.
* (
*
*
.)
* </ul>
Web-
Rendered by www.RenderX.com
Создание и управление DOM Стр. 227 из 626
*/
public String getText(Node node) {
StringBuffer result = new StringBuffer();
if (! node.hasChildNodes()) return "";
// ( )
result.append(getText(subnode));
}
}
return result.toString();
}
Более подробное объяснение этого кода приведено в разделе "Повышение сложности" в
"Когда используется DOM".
Опять же, вы можете упростить этот код, используя API, описанный в разделе "Резюме по
лексическим элементам управления", для изменения типа DOM, которую строит анализатор.
Этот код будет работать с большинством других DOM.
Web-
Rendered by www.RenderX.com
Стр. 228 из 626 Document Object Model
8.6.4. Завершение
Поздравляем! Вы изучили структуру DOM и способы управления ею. Вы имеете приложение
DomEcho, которое можете использовать для отображения структуры DOM. Вы можете
собрать его в GUI-приложение и проводить эксперименты с этой структурой для того,
чтобы увидеть, как различные действия влияют на структуру. Развлекайтесь!
Web-
Rendered by www.RenderX.com
Использование пространства имен Стр. 229 из 626
<title xmlns="http://www.example.com/slideshow">
Overview
</title>
Указанное пространство имен относится к этому элементу и ко всем элементам,
находящимся внутри него.
Web-
Rendered by www.RenderX.com
Стр. 230 из 626 Document Object Model
<SL:slideshow xmlns:SL='http:/www.example.com/slideshow'
...>
...
</SL:slideshow>
Это определение устанавливает SL как префикс, который может быть использован для
уточнения имени текущего элемента и всех элементов внутри него. Поскольку префикс
может использоваться с любыми подчиненными элементами, имеет смысл, как показано
здесь, определить его в корневом элементе XML-документа.
Примечание: URI пространства имен может содержать символы, которые недопустимы в
именах XML, то есть, он не может использоваться в качестве префикса непосредственно.
Определение префикса связывает XML-имя с URI, что позволяет вместо него использовать
префикс. Это также облегчает изменение ссылок на URI в будущем.
Если префикс используется для уточнения имени элемента, завершающий тег тоже
включает префикс, как выделено ниже:
<SL:slideshow xmlns:SL='http:/www.example.com/slideshow'
...>
...
<slide>
<SL:title>Overview</SL:title>
</slide>
...
</SL:slideshow>
Наконец, обратите внимание, что несколько префиксов могут быть определены в одних и
тех же элементах, как показано ниже:
<SL:slideshow xmlns:SL='http:/www.example.com/slideshow'
xmlns:xhtml='urn:...'>
...
</SL:slideshow>
При таком расположении все определения префиксов собраны в одном месте и вы можете
использовать их везде, где этого потребует документ. Этот пример также предлагает
использовать URN для определения префикса xhtml вместо URL. Такое определение
потенциально смогло бы позволить приложению ссылаться на локальную копию XHTML
DTD, или на какую-либо зеркальную версию, с потенциально большим влиянием на
производительность.
Web-
Rendered by www.RenderX.com
Верификация при помощи XML Schema Стр. 231 из 626
...
DocumentBuilderFactory factory =
DocumentBuilderFactory.newInstance()
factory.setNamespaceAware(true);
factory.setValidating(true);
try {
Web-
Rendered by www.RenderX.com
Стр. 232 из 626 Document Object Model
factory.setAttribute(JAXP_SCHEMA_LANGUAGE, W3C_XML_SCHEMA);
}
catch (IllegalArgumentException x) {
// ,
JAXP 1.2
...
}
Поскольку JAXP-совместимые анализаторы по умолчанию не работают с пространством
имен, необходимо установить это свойство для работы верификации схемы. Также вы
устанавливаете атрибут генератора, указывающий используемый язык анализатора. (Для
SAX-анализа вы устанавливаете свойство анализатора, сформированного генератором.)
<documentRoot
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation='YourSchemaDefinition.xsd'
>
...
Первый атрибут определяет префикс XML-пространства имен (xmlns) - "xsi", где "xsi"
означает "XML Schema Instance". Вторая строка указывает схему, которая будет
использоваться для тех элементов документа, которые не имеют префикса пространства
имен - то есть, для элементов, которые вы обычно определяете в простом, обычном XML-
документе. (Вы узнаете, как работать с несколькими пространствами имен в следующем
разделе.)
Вы можете, также, указать файл схемы в приложении, например:
Web-
Rendered by www.RenderX.com
Верификация при помощи XML Schema Стр. 233 из 626
...
factory.setAttribute(JAXP_SCHEMA_SOURCE,
new File(schemaSource));
В вашем распоряжении есть механизмы, позволяющие указывать несколько схем. Мы
узнаем про них далее.
<employee id="...">
<name>....</name>
<tax:form>
...w2 tax form data...
</tax:form>
<hiring:form>
...employment history, etc....
</hiring:form>
</employee>
Очевидно, что содержимое элемента tax:form будет отличаться от содержимого hiring:form
и должно верифицироваться по-разному.
Обратите внимание также, что в этом примере есть пространство имен "по умолчанию",
к которому принадлежат элементы employee и name. Для правильной верификации
документа схема для этого пространства имен должна быть объявлена, также как и для
пространства имен tax и hiring.
Примечание: Пространство имен "по умолчанию" в действительности является
специфическим пространством имен. Оно определяется как "пространство имен без имени".
То есть, вы не можете просто использовать одно пространство имен по умолчанию на этой
неделе, а другое на следующей. Это "непоименованное пространство имен" или "нулевое
пространство имен" похоже на цифру ноль. Она не имеет какого-то значения, но все-таки
Web-
Rendered by www.RenderX.com
Стр. 234 из 626 Document Object Model
точно определена. Поэтому пространство имен, имеющее имя, никогда не может быть
использовано как пространство имен по умолчанию.
Во время анализа каждый элемент в наборе данных будет верифицироваться с
использованием соответствующей схемы, если эти схемы были объявлены. Опять же,
схемы могут быть объявлены как часть XML-данных, или в программе. (Возможно, также,
смешивать объявления, хотя, в общем случае, хорошей идеей является хранение всех
объявлений в одном месте.)
<documentRoot
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="employeeDatabase.xsd"
xsi:schemaLocation=
"http://www.irs.gov/ fullpath/w2TaxForm.xsd
http://www.ourcompany.com/ relpath/hiringForm.xsd"
xmlns:tax="http://www.irs.gov/"
xmlns:hiring="http://www.ourcompany.com/"
>
...
Объявление noNamespaceSchemaLocation похоже на то, что вы видели ранее, то же самое
можно сказать про последние две записи, определяющие префиксы пространств имен tax
и hiring. Новые записи находятся в середине и определяют месторасположение схем,
используемых для каждого пространства имен, на которые есть ссылки в документе.
Объявление xsi:schemaLocation состоит из пар записей, в которых первым элементом
записи является полностью указанный URI пространства имен, а второй элемент содержит
полный или относительный путь к определению схемы. (В общем случае рекомендуется
полный путь, поскольку при этом существует только одна копия схемы.)
Еще одно замечание: префиксы пространства имен не могут быть использованы при
определении месторасположения схемы. Объявление xsi:schemaLocation понимает только
имена пространств имен, не префиксы.
Web-
Rendered by www.RenderX.com
Верификация при помощи XML Schema Стр. 235 из 626
employeeSchema,
taxSchema,
hiringSchema,
};
...
DocumentBuilderFactory factory =
DocumentBuilderFactory.newInstance()
...
factory.setAttribute(JAXP_SCHEMA_SOURCE, schemas);
Здесь массив строк, указывающих на определения схем (.xsd-файлы), передается как
аргумент в метод factory.setAttribute. Обратите внимание на отличия в объявлении схем в
наборе XML-данных:
• Нет специального объявления схемы "по умолчанию" (непоименованной).
• Вы не указываете имя пространства имен, а только определяете указатели на .xsd-
файлы.
Для установки связи с пространством имен анализатор читает .xsd-файлы и находит в них
имя target namespace (целевое пространство имен). Поскольку файлы указаны с URI,
анализатор может использовать EntityResolver (если он определен) для поиска локальной
копии схемы.
Если в определении схемы целевое пространство имен не указано, она связывается с
пространством имен "по умолчанию" (непоименованным, или нулевым). То есть, в
приведенном выше примере вы могли бы увидеть следующие объявления пространств
имен в схемах:
• employeeDatabase.xsd - none
• w2TaxForm.xsd - http://www.irs.gov/
• hiringForm.xsd - http://www.ourcompany.com
На данный момент вы увидели два возможных значения свойства источника схемы при
вызове метода factory.setAttribute(), объект File в factory.setAt-
tribute(JAXP_SCHEMA_SOURCE, new File(schemaSource)) и массив строк в factory.setAt-
tribute(JAXP_SCHEMA_SOURCE, schemas). Вот полный список возможных значений этого
аргумента:
• Строка, указывающая URI схемы
• InputStream с содержимым схемы
• SAX InputSource
• Файл
• Массив объектов, каждый из которых имеет тип, указанный выше.
Web-
Rendered by www.RenderX.com
Стр. 236 из 626 XML Stylesheet Language for Transformations
Примечание: Массив объектов может использоваться только тогда, когда язык схемы
(например, http://java.sun.com/xml/jaxp/properties/schemaLanguage) обладает способностью
ассемблировать схему во время выполнения. И еще: при передаче массива объектов
нельзя иметь две схемы, использующие одно и тоже пространство имен.
Web-
Rendered by www.RenderX.com
Введение в XSLT и XPath Стр. 237 из 626
XSLT
Это язык преобразований, позволяющий определять преобразования из XML в какой-либо
другой формат. Например, XSLT можно использовать для генерирования HTML или другой
XML-структуры. Его можно использовать даже для генерирования обычного текста или
для сохранения информации в каком-нибудь другом формате. (И, как вы узнаете из раздела
"Генерирование XML из произвольной структуры данных", "умное" приложение может
также манипулировать и не XML-данными.)
XPath
В своей основе XSLT - это язык, позволяющий указать, что делать при обнаружении
конкретного элемента. Но при написании программы для различных частей структуры
XML-данных необходимо иметь возможность в любое время указать ту часть структуры,
которая обрабатывается в данный момент времени. Таким языком указания является
XPath. Это механизм адресации, дающий возможность указать путь к элементу, так чтобы,
например, <article><title> можно было отличить от <person><title>. То есть, вы можете
описать различные типы преобразований для различных элементов <title>.
В оставшейся части этого раздела рассматриваются пакеты, составляющие JAXP Trans-
formation API. Затем обсуждаются конфигурационные параметры генератора, используемые
для выбора механизма преобразования Xalan или XSLTC.
Web-
Rendered by www.RenderX.com
Стр. 238 из 626 XML Stylesheet Language for Transformations
Web-
Rendered by www.RenderX.com
Выбор механизма трансформации Стр. 239 из 626
TransformerFactory factory =
TransformerFactory.newInstance();
Transformer xformer = factory.newTransformer(myStyleSheet);
xformer.transform(myXmlInput,
new StreamResult(System.out));
Можно также создать промежуточный объект Templates, который можно сохранить и
использовать повторно, например:
TransformerFactory factory =
TransformerFactory.newInstance();
Templates templates = factory.newTemplates(myStyleSheet);
Transformer xformer = templates.newTransformer();
xformer.transform(myXmlInput,
new StreamResult(System.out));
Примечание: Существуют, также, правила создания таблиц стилей, которые объясняют,
что нужно сделать, а чего следует избегать для получения максимальной
производительности в XSLT. Более подробную информацию по этому вопросу можно
найти на http://xml.apache.org/xalan-j/xsltc/xsltc_performance.html.
Web-
Rendered by www.RenderX.com
Стр. 240 из 626 XML Stylesheet Language for Transformations
javax.xml.transform.TransformerFactory=
org.apache.xalan.xsltc.trax.TransformerFactoryImpl
Хотя иногда невозможно установить это свойство - например, из-за того, что приложение
является сервлетом и изменение системного свойства будет влиять на остальные сервлеты,
выполняющиеся в том же контейнере. В этом случае вы можете создать экземпляр XSLTC-
преобразователя непосредственно:
new org.apache.xalan.xsltc.trax.TransformerFactoryImpl(..)
Вы можете, также, передать значение генератора в приложение и использовать ClassLoader
для создания его экземпляра во время выполнения.
Примечание: Для явного указания Xalan-преобразователя можно использовать значение
org.apache.xalan.processor.TransformerFactoryImpl вместо org.apache.xalan.xsltc.trax.Trans-
formerFactoryImpl.
Существует, также, "умный преобразователь", использующий механизм преобразований
Xalan во время создания объекта Transformer и механизм преобразования XSLTC во время
создания промежуточных объектов Templates. Для получения экземпляра такого
преобразователя используйте значение org.apache.xalan.xsltc.trax.SmartTransformerImpl
для установки системного свойства генератора или для использования этого класса при
прямом создании экземпляра анализатора.
Web-
Rendered by www.RenderX.com
Как работает XPath Стр. 241 из 626
<xsl:template match="//LIST">
Web-
Rendered by www.RenderX.com
Стр. 242 из 626 XML Stylesheet Language for Transformations
...
</xsl:template>
Выражение //LIST выбирает набор узлов LIST из входного потока. Дополнительные
инструкции в шаблоне указывают системе, что делать с этими узлами.
Выбранный таким выражением набор узлов определяет контекст, в котором другие
выражения шаблона выполняются. Этот контекст может рассматриваться как полный
набор - например, при определении количества его узлов.
Контекст может рассматриваться, также, как простой член набора, поскольку каждый член
обрабатывается один за другим. Например, в шаблоне LIST выражение @type относится
к атрибуту type текущего узла LIST. (Подобным же образом, выражение @* относится ко
всем атрибутам текущего элемента LIST.)
Web-
Rendered by www.RenderX.com
Как работает XPath Стр. 243 из 626
Web-
Rendered by www.RenderX.com
Стр. 244 из 626 XML Stylesheet Language for Transformations
Web-
Rendered by www.RenderX.com
Как работает XPath Стр. 245 из 626
9.3.11. XPath-функции
Данный раздел завершается обзором XPath-функций. Вы можете использовать их для
выбора набора узлов, точно также как использовали бы спецификацию элементов, которую
вы уже видели. Другие функции возвращают строку, число или логическое значение.
Например, выражение /PROJECT/text() выдает строковое значение узлов PROJECT.
Многие функции зависят от текущего контекста. В приведенном выше примере контекстом
для каждого вызова функции text() является выбранный в данное время узел PROJECT.
Есть много XPath-функций - слишком много для их детального описания. Здесь приведен
их список вместе с кратким описанием их действия.
Примечание: Просмотрите список функций для ознакомления. Более подробная
информация находится в "XPath Specification".
Web-
Rendered by www.RenderX.com
Стр. 246 из 626 XML Stylesheet Language for Transformations
Web-
Rendered by www.RenderX.com
Как работает XPath Стр. 247 из 626
• lang(string) - возвращает true, если язык узла контекста (указанный в атрибуте xml:Lang)
такой же (или подчиненный ему), как указанный язык. Например: Lang("en") возвращает
true для <PARA_xml:Lang="en">...</PARA>
9.3.12. Резюме
Операторы, функции, групповые имена и механизмы адресации узлов в XPath могут
комбинироваться различными способами. Это введение должно было дать вам хорошие
начальные знания для определения образца, необходимого при решении любой конкретной
задачи.
Web-
Rendered by www.RenderX.com
Стр. 248 из 626 XML Stylesheet Language for Transformations
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.FactoryConfigurationError;
import javax.xml.parsers.ParserConfigurationException;
import org.xml.sax.SAXException;
import org.xml.sax.SAXParseException;
import org.w3c.dom.Document;
import org.w3c.dom.DOMException;
import java.io.*;
Web-
Rendered by www.RenderX.com
Запись DOM в XML-файл Стр. 249 из 626
DocumentBuilderFactory factory =
DocumentBuilderFactory.newInstance();
//factory.setNamespaceAware(true);
//factory.setValidating(true);
try {
File f = new File(argv[0]);
DocumentBuilder builder =
factory.newDocumentBuilder();
document = builder.parse(f);
//
( )
Exception x = spe;
if (spe.getException() != null)
x = spe.getException();
x.printStackTrace();
// (
)
Exception x = sxe;
if (sxe.getException() != null)
x = sxe.getException();
x.printStackTrace();
pce.printStackTrace();
Web-
Rendered by www.RenderX.com
Стр. 250 из 626 XML Stylesheet Language for Transformations
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerConfigurationException;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import java.io.*;
Здесь вы добавили набор классов, которые должны теперь быть стандартным шаблоном:
сущность (Transformer), генератор для его создания (TransformerFactory) и исключительные
ситуации, которые могут быть сгенерированы каждым из них. Поскольку преобразование
всегда имеет источник и результат, далее добавляются классы, необходимые для
использования DOM в качестве источника (DomSource) и выходного потока в качестве
результата (StreamResult).
Далее, добавим код для выполнения преобразования:
try {
File f = new File(argv[0]);
DocumentBuilder builder = factory.newDocumentBuilder();
document = builder.parse(f);
// Transformer
Web-
Rendered by www.RenderX.com
Запись DOM в XML-файл Стр. 251 из 626
TransformerFactory tFactory =
TransformerFactory.newInstance();
Transformer transformer = tFactory.newTransformer();
//
( )
Throwable x = tce;
if (tce.getException() != null)
x = tce.getException();
x.printStackTrace();
//
( )
Throwable x = te;
if (te.getException() != null)
x = te.getException();
x.printStackTrace();
Web-
Rendered by www.RenderX.com
Стр. 252 из 626 XML Stylesheet Language for Transformations
import javax.xml.transform.OutputKeys;
...
if (document.getDoctype() != null){
String systemValue = (new
File(document.getDoctype().getSystemId())).getName();
transformer.setOutputProperty(
OutputKeys.DOCTYPE_SYSTEM, systemValue
);
}
Web-
Rendered by www.RenderX.com
Запись DOM в XML-файл Стр. 253 из 626
<item/>
<item>Who <em>buys</em> WonderWidgets</item>
</slide>
</slideshow>
Примечание: Порядок атрибутов может меняться в зависимости от используемого
анализатора.
Дополнительная информация по настройке генератора и обработке ошибок верификации
находится в разделах "Чтение XML-данных в DOM", "Дополнительная информация".
import org.w3c.dom.Document;
import org.w3c.dom.DOMException;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
Следующее действие - найти хороший узел для эксперимента. Добавьте выделенный ниже
код для выбора первого элемента <slide>:
try {
File f = new File(argv[0]);
DocumentBuilder builder = factory.newDocumentBuilder();
document = builder.parse(f);
// <slide> DOM
NodeList list = document.getElementsByTagName("slide");
Node node = list.item(0);
Наконец, сделайте показанные ниже изменения для построения объекта source, состоящего
из поддерева, начинающегося с этого узла:
Web-
Rendered by www.RenderX.com
Стр. 254 из 626 XML Stylesheet Language for Transformations
9.4.4.1. Очистка
Выполните показанные ниже изменения для отмены добавлений, сделанных вами в этом
разделе. (Эти изменения содержатся в файле TransformationApp04.java.)
Import org.w3c.dom.DOMException;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
...
try {
...
// <slide> DOM
NodeList list = document.getElementsByTagName("slide");
Node node = list.item(0);
...
DOMSource source = new DOMSource(node);
StreamResult result = new StreamResult(System.out);
transformer.transform(source, result);
9.4.5. Резюме
Вы узнали, как использовать преобразователь для записи DOM и как использовать
поддерево DOM в качестве объекта source для преобразования. В следующем разделе
вы увидите, как используется преобразователь для создания XML из любой структуры
данных, которую можно проанализировать.
Web-
Rendered by www.RenderX.com
Генерирование DOM из произвольной структуры данных Стр. 255 из 626
Web-
Rendered by www.RenderX.com
Стр. 256 из 626 XML Stylesheet Language for Transformations
Экспорт адресной книги создает показанный ниже файл. Интересующая нас часть файл
выделена жирным шрифтом.
import java.io.*;
Web-
Rendered by www.RenderX.com
Генерирование DOM из произвольной структуры данных Стр. 257 из 626
System.err.println (
"Usage: java AddressBookReader filename");
System.exit (1);
}
String filename = argv[0];
File f = new File(filename);
AddressBookReader01 reader = new AddressBookReader01();
reader.parse(f);
}
/** */
public void parse(File f)
{
try {
//
//
.
String line = br.readLine();
while (null != (line = br.readLine())) {
if (line.startsWith("xmozillanickname: "))
break;
}
output("nickname", "xmozillanickname", line);
line = br.readLine();
output("email", "mail", line);
line = br.readLine();
output("html", "xmozillausehtmlmail", line);
line = br.readLine();
output("firstname","givenname", line);
line = br.readLine();
output("lastname", "sn", line);
line = br.readLine();
output("work", "telephonenumber", line);
line = br.readLine();
output("home", "homephone", line);
line = br.readLine();
output("fax", "facsimiletelephonenumber",
Web-
Rendered by www.RenderX.com
Стр. 258 из 626 XML Stylesheet Language for Transformations
line);
line = br.readLine();
output("pager", "pagerphone", line);
line = br.readLine();
output("cell", "cellphone", line);
}
catch (Exception e) {
e.printStackTrace();
}
}
nickname: Fred
Web-
Rendered by www.RenderX.com
Генерирование DOM из произвольной структуры данных Стр. 259 из 626
email: Fred@barneys.house
html: TRUE
firstname: Fred
lastname: Flintstone
work: 999-Quarry
home: 999-BedrockLane
fax: 888-Squawk
pager: 777-pager
cell: 555-cell
Думаю, что можно согласиться с тем, что это немного более читаемо.
import java.io.*;
import org.xml.sax.*;
import org.xml.sax.helpers.AttributesImpl;
Затем, измените приложение так, чтобы оно расширяло XmlReader. Эти изменения
преобразуют приложение в анализатор, генерирующий соответствующие SAX-события.
Web-
Rendered by www.RenderX.com
Стр. 260 из 626 XML Stylesheet Language for Transformations
//
// .
String nsu = ""; // NamespaceURI
Attributes atts = new AttributesImpl();
String rootElement = "addressbook";
try {
//
Web-
Rendered by www.RenderX.com
Генерирование DOM из произвольной структуры данных Стр. 261 из 626
java.io.Reader r = input.getCharacterStream();
BufferedReader Br = new BufferedReader(r);
Примечание: В следующем разделе вы создадите входной объект source и все, что вы
поместите в него, фактически и будет BufferedReader. Но AddressBookReader мог бы когда-
нибудь использоваться кем-то еще. Это действие дает гарантию того, что обработка будет
эффективной независимо от используемого считывателя.
Следующее действие - изменить метод parse для генерирования SAX-событий в начале
документа и корневого элемента. Для этого добавьте выделенный ниже код:
/** */
public void parse(InputSource input)
...
{
try {
...
//
.
String line = br.readLine();
while (null != (line = br.readLine())) {
if (line.startsWith("xmozillanickname: ")) break;
}
if (handler==null) {
throw new SAXException("No content handler");
}
handler.startDocument();
handler.startElement(nsu, rootElement,
rootElement, atts);
handler.ignorableWhitespace("\n".toCharArray(),
0, //
1 //
);
handler.endElement(nsu, rootElement, rootElement);
handler.endDocument();
}
Web-
Rendered by www.RenderX.com
Стр. 262 из 626 XML Stylesheet Language for Transformations
catch (Exception e) {
...
Здесь вы, прежде всего, проверили, правильно ли настроен анализатор на ContentHandler.
(В данном приложении мы больше ни о чем не беспокоимся.) Затем вы сгенерировали
события для начала документа и корневого элемента, и, в завершение, послали конечные
события для корневого элемента и для документа.
Некоторые моменты достойны внимания:
• Мы не беспокоимся о посылке события setDocumentLocator, поскольку оно не
обязательно. Там, где это важно, оно могло бы посылаться непосредственно перед
событием startDocument.
• Мы сгенерировали событие ignorableWhitespace перед концом корневого элемента. Это
тоже не обязательно, но значительно улучшает читаемость выводимой информации,
что вы вскоре увидите. (В данном случае пробел состоит из одного символа новой
строки, который передается также, как символы передаются в метод characters: в виде
массива символов, начального индекса и длины.)
Теперь, когда для документа и корневого элемента генерируются SAX-события, изменим
метод output для генерирования соответствующих событий элемента для каждого элемента
данных. Выполните следующие изменения:
Web-
Rendered by www.RenderX.com
Генерирование DOM из произвольной структуры данных Стр. 263 из 626
/**
. */
public void setContentHandler(ContentHandler handler) {
this.handler = handler;
}
/**
. */
public ContentHandler getContentHandler() {
return this.handler;
}
Существует еще несколько методов, которые должны быть реализованы для интерфейса
XmlReader. Для задач этого приложения мы создадим нулевые методы для них всех. Для
рабочего приложения вы, возможно, решите реализовать методы обработчика ошибок
для создания более надежного приложения. А сейчас просто добавьте выделенный ниже
код для создания нулевых методов:
/**
. */
public void setErrorHandler(ErrorHandler handler)
{ }
/** .
Web-
Rendered by www.RenderX.com
Стр. 264 из 626 XML Stylesheet Language for Transformations
*/
public ErrorHandler getErrorHandler()
{ return null; }
Наконец, добавьте выделенный ниже код, создающий нулевые методы для оставшегося
интерфейса XmlReader. (Большинство из них имеют значение для реального SAX-
анализатора, но не имеют смысла для похожего на наше приложение по преобразованию
данных.)
/** XML-
(URI). */
public void parse(String systemId)
throws IOException, SAXException
{ }
/**
DTD- . */
public DTDHandler getDTDHandler()
{ return null; }
/**
. */
public EntityResolver getEntityResolver()
{ return null; }
/**
. */
public void setEntityResolver(EntityResolver resolver)
{ }
/**
DTD- . */
public void setDTDHandler(DTDHandler handler)
{ }
/** . */
public Object getProperty(String name)
{ return null; }
/** . */
public void setProperty(String name, Object value)
Web-
Rendered by www.RenderX.com
Генерирование DOM из произвольной структуры данных Стр. 265 из 626
{ }
/** . */
public void setFeature(String name, boolean value)
{ }
/** . */
public boolean getFeature(String name)
{ return false; }
Поздравляем! Вы имеете анализатор, который можно использовать для генерации SAX-
событий. В следующем разделе вы будете использовать его для построения объекта
SAXSource, который позволит вам преобразовать данные в XML.
import org.xml.sax.SAXException;
import org.xml.sax.SAXParseException;
import org.xml.sax.ContentHandler;
import org.xml.sax.InputSource;
import org.w3c.dom.Document;
import org.w3c.dom.DOMException;
...
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.sax.SAXSource;
import javax.xml.transform.stream.StreamResult;
Затем, удалите несколько других пережитков наших упражнений с DOM и добавьте код
для создания экземпляра AddressBookReader:
Web-
Rendered by www.RenderX.com
Стр. 266 из 626 XML Stylesheet Language for Transformations
try {
File f = new File(argv[0]);
DocumentBuilder builder =
factory.newDocumentBuilder();
document = builder.parse(f);
Знаете что! Вы почти у цели. Еще совсем немного действий. Добавьте выделенный ниже
код для создания объекта SAXSource:
// Transformer
...
Transformer transformer = tFactory.newTransformer();
//
SAX
FileReader fr = new FileReader(f);
BufferedReader br = new BufferedReader(fr);
InputSource inputSource = new InputSource(br);
SAXSource source = new SAXSource(saxReader, inputSource);
Web-
Rendered by www.RenderX.com
Генерирование DOM из произвольной структуры данных Стр. 267 из 626
//
,
Exception x = spe;
if (spe.getException() != null)
x = spe.getException();
x.printStackTrace();
// ( )
Exception x = sxe;
if (sxe.getException() != null)
x = sxe.getException();
x.printStackTrace();
Web-
Rendered by www.RenderX.com
Стр. 268 из 626 XML Stylesheet Language for Transformations
Web-
Rendered by www.RenderX.com
Преобразование XML-данных при помощи XSLT Стр. 269 из 626
• <LIST> - Список
• <ITEM> - Запись в списке
• <NOTE> - Отступление, которое может быть смещением от основного текста
Немного необычным в этой структуре является то, что мы не хотим создавать отдельный
тег элемента для заголовка секции. Такие элементы обычно создаются для того, чтобы
отличить текст заголовка (и любых тегов, которые он содержит) от тела секции (то есть,
любых структурных элементов, расположенных ниже заголовка).
Вместо этого мы разрешаем заголовку плавно переходить в тело секции. Это добавляет
некоторую сложность в таблицу стилей, но дает нам шанс исследовать механизмы выбора
шаблонов XSLT. Это также соответствует нашему интуитивному представлению структуры
документа, где текст заголовка непосредственно предшествует структурным элементам,
что может упростить структурное редактирование.
Примечание: Однако такую структуру верифицировать не легко, поскольку XML-модель
смешанного содержимого позволяет тексту находиться в любом месте секции, тогда как
мы хотим ограничить текст и встроенные элементы так, чтобы они появлялись только
перед первым структурным элементом тела секции. Основанный на утверждениях
верификатор (Schematron) может сделать это, но большинство других механизмов
верификации - нет. Поэтому мы обойдемся без определения DTD для типа документов.
В этой структуре секции могут быть вложенными. Глубина вложения будет определять
тип HTML-форматирования, используемого для заголовка секций (например, h1 или h2).
Использование простого тега SECT (вместо пронумерованных секций) также полезно при
структурном редактировании, потому что дает возможность перемещать секции по желанию
без необходимости беспокоится об изменении нумерации для этой секции или для любых
других секций, которые могут быть затронуты перемещением.
Для списков мы будем использовать атрибут type для указания следующих видов списка:
unordered (список с буллитами), alpha (пронумерованный маленькими буквами), ALPHA
(пронумерованный большими буквами), numbered.
Мы, также, разрешим использование некоторых встроенных тегов, изменяющих внешний
вид текста:
• <B> - жирный
• <I> - наклонный
• <U> - подчеркнутый
• <DEF> - определение
• <LINK> - ссылка на URL
Примечание: Встроенный тег не генерирует конец строки, поэтому изменение стиля,
вызванное встроенным тегом, не влияет на поток текста на странице (хотя влияет на его
внешний вид). С другой стороны, структурный тег разделяет новый сегмент текста, поэтому
как минимум он всегда генерирует конец строки в дополнение к другим изменениям
формата.
Тег <DEF> будет использоваться для терминов, определенных в тексте. Такие термины
будут отображаться наклонным шрифтом, как принято в документах. Но использование
специального тега в XML позволит программе индексации найти такие определения и
Web-
Rendered by www.RenderX.com
Стр. 270 из 626 XML Stylesheet Language for Transformations
<?xml version="1.0"?>
<ARTICLE>
<TITLE>A Sample Article</TITLE>
<SECT>The First Major Section
<PARA>This section will introduce a subsection.</PARA>
<SECT>The Subsection Heading
<PARA>This is the text of the subsection.
</PARA>
</SECT>
</SECT>
</ARTICLE>
Обратите внимание на то, что в XML-файле подсекции полностью содержатся внутри
основной секции. (В HTML, с другой стороны, заголовки не содержат тела секции.) В
результате получается структура, которую тяжело редактировать в обычной форме, но
намного легче редактировать с помощью структурного редактора.
Имея ориентированный на древовидную структуру XML-редактор, понимающий встроенные
теги, подобные <B> и <I>, будет возможно редактировать статью этого типа в
табулированной форме без необходимости сложной таблицы стилей. (Такой редактор
позволил бы писателю сконцентрироваться на структуре статьи, оставляя создание схемы
Web-
Rendered by www.RenderX.com
Преобразование XML-данных при помощи XSLT Стр. 271 из 626
<ARTICLE>
<TITLE>A Sample Article
<SECT>The First Major Section
<PARA>This section will introduce a subsection.
<SECT>The Subheading
<PARA>This is the text of the subsection. Note that
...
Примечание: В настоящее время редакторы, понимающие древовидную структуру,
существуют, но они интерпретируют встроенные теги, подобные <B> и <I>, так же как и
остальные структурные теги, что может сделать "табулированную" структуру немного
трудной для чтения.
</xsl:stylesheet>
А сейчас настройте ее для генерирования HTML-совместимого вывода:
<xsl:stylesheet
...
>
<xsl:output method="html"/>
...
Web-
Rendered by www.RenderX.com
Стр. 272 из 626 XML Stylesheet Language for Transformations
</xsl:stylesheet>
Мы детально объясним необходимость этой записи позже. А сейчас отметим, что если вы
хотите выводить что-либо, кроме формально-правильного XML, подобный тег <xsl:output>,
указывающий либо "text", либо "html", необходим. (Значение по умолчанию - "xml".)
Примечание: При указании XML-вывода вы можете добавить атрибут indent для
генерирования красивого протабулированного XML-вывода. Спецификация выглядит так:
<xsl:output method="xml" indent="yes"/>.
<xsl:template match="/">
<html><body>
<xsl:apply-templates/>
</body></html>
</xsl:template>
</xsl:stylesheet>
Новые XSL-команды выделены жирным шрифтом. (Обратите внимание, что они определены
в пространстве имен "xsl".) Команда <xsl:apply-templates> обрабатывает потомков текущего
узла. В данном случае текущим узлом является корневой узел.
Несмотря на свою простоту, этот пример иллюстрирует некоторое количество важных
идей, поэтому стоит его внимательно рассмотреть. Первым моментом является то, что
таблица стилей содержит несколько шаблонов, определенных тегом <xsl:template>. Каждый
шаблон содержит атрибут match, который выбирает элементы, к которым относится шаблон,
используя механизм адресации XPath, описанный в разделе "Как работает XPath".
Внутри шаблона теги, не начинающиеся с префикса пространства имен xsl:, просто
копируются. Следующие за ними символы новой строки и пробелы тоже копируются, что
делает выводимый результат более читаемым.
Примечание: Если отсутствует символ новой строки, пробел обычно игнорируется. Чтобы
в данном случае включить пробел в вывод, или включить другой текст, можно использовать
тег <xsl:text>. По существу таблица стилей XSLT ожидает обработки тегов. Поэтому все,
что она видит, должно быть либо тегом <xsl:..>, либо каким-то другим тегом, либо пробелом.
Web-
Rendered by www.RenderX.com
Преобразование XML-данных при помощи XSLT Стр. 273 из 626
В данном случае не XSL-теги являются тегами HTML. Поэтому при совпадении корневого
тега XSLT выводит начальный тег HTML, обрабатывает все шаблоны, относящиеся к
потомкам корневого тега, и затем выводит завершающий тег HTML.
<xsl:template match="/ARTICLE/TITLE">
<h1 align="center"> <xsl:apply-templates/> </h1>
</xsl:template>
</xsl:stylesheet>
В данном случае вы указываете полный путь к элементу TITLE и выводите несколько
HTML-тегов для оформления текста названия в большой, отцентрированный заголовок.
В данном случае тег apply-templates гарантирует, что если название содержит какой-либо
встроенный тег, например наклонный шрифт, ссылки или подчеркивания, они тоже будут
обработаны.
Более важно, что команда apply-templates вызывает обработку текста названия. Аналогично
модели данных DOM, модель данных XSLT основана на концепции содержания текстовых
узлов в узлах элементов (которые, в свою очередь, могут содержаться в других узлах
элементов и т.д.). Эта иерархическая структура составляет исходное дерево. Существует
также дерево результата, содержащее выводимые данные.
XSLT работает, преобразуя исходное дерево в дерево результата. Для визуализации
результата XSLT-операций полезно понимать структуру этих деревьев и их содержимое.
(Более подробная информация по этому предмету приведена в разделе "Модель данных
XSLT/XPath".)
<xsl:template match="/ARTICLE/SECT">
<h2> <xsl:apply-templates
select="text()|B|I|U|DEF|LINK"/> </h2>
<xsl:apply-templates select="SECT|PARA|LIST|NOTE"/>
</xsl:template>
</xsl:stylesheet>
Здесь вы указали путь к самым верхним элементам SECT. Но сейчас вы применили
шаблоны в два шага, используя атрибут select. На первом шаге вы выбрали текстовые
узлы при помощи функции XPath text(), так же как и встроенные элементы, такие как B и
I. (Символ вертикальной черты (|) используется для соответствия нескольких элементов
Web-
Rendered by www.RenderX.com
Стр. 274 из 626 XML Stylesheet Language for Transformations
- текста, или тега bold, или тега italics и т.д.) На втором шаге вы выбрали другие структурные
элементы, содержащиеся в файле - секции, параграфы, списки и узлы.
Использование атрибута select позволяет разместить текст и встроенные элементы между
тегами <h2>…</h2>, гарантируя, что все структурные теги в секции будут обработаны
после них. Другими словами, вы гарантируете, что вложение заголовков в XML-документе
не отражается на HTML-форматировании, что важно для вывода в формате HTML.
В общем случае использование предложения select позволяет вам применить все шаблоны
к набору информации, доступному в текущем контексте. Например, этот шаблон выбирает
все атрибуты текущего узла:
<xsl:apply-templates select="@*"/></attributes>
Далее, добавьте практически идентичный шаблон для обработки подзаголовков, вложенных
на один уровень глубже:
<xsl:template match="/ARTICLE/SECT/SECT">
<h3> <xsl:apply-templates
select="text()|B|I|U|DEF|LINK"/> </h3>
<xsl:apply-templates select="SECT|PARA|LIST|NOTE"/>
</xsl:template>
</xsl:stylesheet>
<xsl:template match="/ARTICLE/SECT/SECT/SECT">
<xsl:message terminate="yes">
Error: Sections can only be nested 2 deep.
</xsl:message>
</xsl:template>
</xsl:stylesheet>
Web-
Rendered by www.RenderX.com
Преобразование XML-данных при помощи XSLT Стр. 275 из 626
<xsl:template match="PARA">
<p><xsl:apply-templates/></p>
</xsl:template>
</xsl:stylesheet>
...
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamSource;
import javax.xml.transform.stream.StreamResult;
...
Web-
Rendered by www.RenderX.com
Стр. 276 из 626 XML Stylesheet Language for Transformations
DocumentBuilder builder =
factory.newDocumentBuilder();
document = builder.parse(f datafile);
...
StreamSource stylesource =
new StreamSource(stylesheet);
Transformer transformer =
Factory.newTransformer(stylesource);
...
Этот код использует файл для создания объекта StreamSource и передает исходный объект
в класс генератора для создания преобразователя.
Примечание: Вы можете немного упростить код, удалив полностью класс DOMSource.
Вместо создания объекта DOMSource для XML-файла создайте для него объект Stream-
Source, так же как и для таблицы стилей.
Откомпилируйте и выполните программу, используя article1a.xsl с article1.xml. Результат
работы должен выглядеть примерно так:
<html>
<body>
</h2>
Web-
Rendered by www.RenderX.com
Преобразование XML-данных при помощи XSLT Стр. 277 из 626
</h3>
</p>
</body>
</html>
В выводе существует порядочное число лишних пробелов. В следующем разделе вы
узнаете, как удалить большинство из них.
<xsl:stylesheet ...
>
<xsl:output method="html"/>
<xsl:strip-space elements="SECT"/>
...
Эта команда указывает XSL удалить любые текстовые узлы под элементом SECT, не
содержащим ничего, кроме пробелов. Узлы, содержащие текст не из пробелов, затронуты
не будут, как и другие типы узлов.
Теперь после выполнения программы результат будет выглядеть примерно так:
<html>
<body>
Web-
Rendered by www.RenderX.com
Стр. 278 из 626 XML Stylesheet Language for Transformations
</h3>
<p>This is the text of the subsection.
</p>
</body>
</html>
Это действительно улучшение. Еще остались символы новой строки и пробелы после
заголовков, но их выводит сам XML:
<xsl:template match="text()">
<xsl:value-of select="normalize-space()"/>
</xsl:template>
</xsl:stylesheet>
Результат работы теперь выглядит примерно так:
<html>
<body>
<h1 align="center">A Sample Article</h1>
<h2>The First Major Section</h2>
<p>This section will introduce a subsection.</p>
<h3>The Subsection Heading</h3>
<p>This is the text of the subsection.</p>
</body>
</html>
Web-
Rendered by www.RenderX.com
Преобразование XML-данных при помощи XSLT Стр. 279 из 626
<?xml version="1.0"?>
<ARTICLE>
<TITLE>A Sample Article</TITLE>
<SECT>The First Major Section
...
Web-
Rendered by www.RenderX.com
Стр. 280 из 626 XML Stylesheet Language for Transformations
</SECT>
<SECT>The Second Major Section
<PARA>This section adds a LIST and a NOTE.
<PARA>Here is the LIST:
<LIST type="ordered">
<ITEM>Pears</ITEM>
<ITEM>Grapes</ITEM>
</LIST>
</PARA>
<PARA>And here is the NOTE:
<NOTE>Don't forget to go to the hardware store
on your way to the grocery!
</NOTE>
</PARA>
</SECT>
</ARTICLE>
Примечание: Хотя список и примечание в XML-файле содержатся в соответствующих
параграфах, в действительности нет различий, содержатся они там или нет - в любом
случае генерируемый HTML будет одним и тем же. Но такая структура облегчит работу с
ними в структурном редакторе.
<xsl:template match="PARA">
<p><xsl:apply-templates/></p>
<p> <xsl:apply-templates select="text()|B|I|U|DEF|LINK"/>
</p>
<xsl:apply-templates select="PARA|LIST|NOTE"/>
</xsl:template>
Это изменение использует ту же технику, которая применялась вами в заголовках секций.
Единственное отличие - элементы SECT не ожидаются внутри параграфа. (Однако параграф
мог бы легко существовать внутри другого параграфа.)
<xsl:template match="LIST">
<xsl:if test="@type='ordered'">
<ol>
<xsl:apply-templates/>
Web-
Rendered by www.RenderX.com
Преобразование XML-данных при помощи XSLT Стр. 281 из 626
</ol>
</xsl:if>
<xsl:if test="@type='unordered'">
<ul>
<xsl:apply-templates/>
</ul>
</xsl:if>
</xsl:template>
</xsl:stylesheet>
Тег <xsl:if> использует атрибут test="" для указания логического условия. В данном случае,
проверяется значение атрибута type и генерируемый список изменяется в зависимости от
значения (ordered или unordered).
Два важных замечания:
• Не существует предложения else, а также операторов return или exit, поэтому мы
используем два тега <xsl:if> для записи двух свойств. (Либо мог бы использоваться тег
<xsl:choose>, обеспечивающий функцию выбора.)
• Вокруг значений атрибутов требуется наличие одинарных кавычек. В противном случае
XSLT-процессор пытается интерпретировать слово ordered как XPath функцию, а не
строку.
А сейчас завершим обработку LIST, добавив обработку элементов ITEM:
<xsl:template match="ITEM">
<li><xsl:apply-templates/>
</li>
</xsl:template>
</xsl:stylesheet>
Web-
Rendered by www.RenderX.com
Стр. 282 из 626 XML Stylesheet Language for Transformations
<xsl:template match="NOTE">
<blockquote><b>Note:</b><br/>
<xsl:apply-templates/>
</p></blockquote>
</xsl:template>
</xsl:stylesheet>
Этот код поднимает один интересный вопрос, возникающий из-за включения тега <br/>.
Для того, чтобы XML был формально-правильным, тег должен быть указан в таблице
стилей как <br/>, но этот тег не распознается многими броузерами. И хотя многие броузеры
распознают последовательность <br></br>, они считают ее разрывом параграфа, а не
одной строки.
Другими словами, преобразование должно генерировать тег <br>, а таблица стилей должна
указывать <br/>. Это основная причина добавления специального тега output в таблице
стилей, которое мы сделали ранее:
Web-
Rendered by www.RenderX.com
Преобразование XML-данных при помощи XSLT Стр. 283 из 626
<, она в генерируемом тексте будет выглядеть как символ <. А при генерировании XML
ссылка на сущность < в таблице стилей осталась бы неизмененной и появлялась бы как
< в генерируемом тексте.
Примечание: Если вы действительно хотите, чтобы < генерировалась как часть вывода
HTML, вам необходимо закодировать ее так: &lt; - эта последовательность
преобразуется в < поскольку только & преобразуется в символ &.
...
<h2>The Second Major Section</h2>
<p>This section adds a LIST and a NOTE.</p>
<p>Here is the LIST:</p>
<ol>
<li>Pears</li>
<li>Grapes</li>
</ol>
<p>And here is the NOTE:</p>
<blockquote>
<b>Note:</b>
<br>Don't forget to go to the hardware store on your way to the
grocery!
</blockquote>
<?xml version="1.0"?>
<ARTICLE>
<TITLE>A Sample Article</TITLE>
<SECT>The First Major Section
Web-
Rendered by www.RenderX.com
Стр. 284 из 626 XML Stylesheet Language for Transformations
...
</SECT>
<SECT>The Second Major Section
...
</SECT>
<SECT>The <I>Third</I> Major Section
<PARA>In addition to the inline tag in the heading,
this section defines the term <DEF>inline</DEF>,
which literally means "no line break". It also
adds a simple link to the main page for the Java
platform (<LINK>http://java.sun.com</LINK>),
as well as a link to the
<LINK target="http://java.sun.com/xml">XML</LINK>
page.
</PARA>
</SECT>
</ARTICLE>
Теперь обработайте встроенные в параграф элементы <DEF>, переименовывая их в теги
HTML для наклонного шрифта:
<xsl:template match="DEF">
<i> <xsl:apply-templates/> </i>
</xsl:template>
Затем, закомментируйте нормализацию текстового узла. Она выполнила свою задачу, и
сейчас вам необходимо сохранить важные пробелы:
<!--
<xsl:template match="text()">
<xsl:value-of select="normalize-space()"/>
</xsl:template>
-->
Это изменение защищает нас от потери пробелов перед такими тегами, как <I> и <DEF>.
(Попробуйте выполнить эту программу без такого изменения и посмотрите на результат.)
А теперь обработаем основные встроенные HTML-элементы, такие как <B>, <I>, <U> для
выделения текста жирным, наклонным и подчеркнутым шрифтами.
<xsl:template match="B|I|U">
<xsl:element name="{name()}">
<xsl:apply-templates/>
Web-
Rendered by www.RenderX.com
Преобразование XML-данных при помощи XSLT Стр. 285 из 626
</xsl:element>
</xsl:template>
Тег <xsl:element> позволяет вам вычислить элемент, который вы хотите сгенерировать.
Здесь вы генерируете соответствующий встроенный тег, используя имя текущего элемента.
В частности, обратите внимание на использование фигурных скобок ({}) в выражении
name= "..". Эти фигурные скобки указывают, чтобы текст внутри них был обработан как
XPath-выражение, а не как символьная строка. В данном случае вызывается функция
XPath name(), возвращающая имя текущего узла.
Фигурные скобки распознаются везде, где может встретиться шаблон значения атрибута.
(Шаблоны значения атрибута определены в разделе 7.6.2 Спецификации XSLT и
появляются в нескольких местах в определении шаблона.) В таких выражениях фигурные
скобки могут, также, использоваться для ссылки на значение атрибута, {@foo} или на
содержимое элемента {foo}.
Примечание: Вы можете, также, генерировать атрибуты, используя <xsl:attribute>. Для
дополнительной информации обратитесь к разделу 7.1.3 Спецификации XSLT.
Последним оставшимся элементом является тег LINK. Простейшим способом обработки
этого тега является установка именованного шаблона, который мы можем использовать
с параметром:
<xsl:template name="htmLink">
<xsl:param name="dest" select="UNDEFINED"/>
<xsl:element name="a">
<xsl:attribute name="href">
<xsl:value-of select="$dest"/>
</xsl:attribute>
<xsl:apply-templates/>
</xsl:element>
</xsl:template>
Основным отличием этого шаблона от использовавшихся ранее является то, что вместо
указания предложения match вы дали шаблону имя при помощи предложения name="".
Поэтому этот шаблон выполняется только при его вызове.
Внутри шаблона вы также указали параметр с именем dest, используя тег <xsl:param>.
Для некоторой защиты от ошибок вы использовали предложение select для присвоения
этому параметру значения по умолчанию UNDEFINED. Для ссылки к переменной в теге
<xsl:value-of> вы указали "$dest".
Примечание: Вспомните, что запись в кавычках интерпретируется как выражение, если
она не заключается далее в одинарные кавычки. Вот почему одинарные кавычки были
ранее необходимы в "@type='ordered'" - для интерпретации ordered как строки.
Тег <xsl:element> генерирует элемент. Ранее мы могли просто указать желаемый элемент,
кодируя, например, <html>. Но здесь вы динамически генерируете содержимое анкера
HTML (<a>) в теле тега <xsl:element>, а также динамически генерируете атрибут href,
используя тег <xsl:attribute>.
Web-
Rendered by www.RenderX.com
Стр. 286 из 626 XML Stylesheet Language for Transformations
<xsl:template match="LINK">
<xsl:if test="@target">
<!--Target attribute specified.-->
<xsl:call-template name="htmLink">
<xsl:with-param name="dest" select="@target"/>
</xsl:call-template>
</xsl:if>
</xsl:template>
<xsl:template name="htmLink">
...
Предложение test="@target" возвращает true, если в теге LINK существует атрибут target.
То есть, этот тег <xsl-if> генерирует HTML-ссылки, когда текст ссылки и назначение,
определенное для нее, различны.
Тег <xsl:call-template> вызывает именованный шаблон, в то время как <xsl:with-param>
указывает параметр, используя предложение name, и его значение, используя предложение
select.
В качестве последнего действия в процессе создания таблицы стилей добавьте
приведенный ниже тег <xsl-if> для обработки тегов LINK, не имеющих атрибута target.
<xsl:template match="LINK">
<xsl:if test="@target">
...
</xsl:if>
<xsl:if test="not(@target)">
<xsl:call-template name="htmLink">
<xsl:with-param name="dest">
<xsl:apply-templates/>
</xsl:with-param>
</xsl:call-template>
</xsl:if>
</xsl:template>
Предложение not(…) инвертирует предыдущий тест (вспомните, что не существует
предложения else). То есть, эта часть шаблона интерпретируется тогда, когда атрибут
Web-
Rendered by www.RenderX.com
Преобразование XML-данных при помощи XSLT Стр. 287 из 626
...
<h2>The <I>Third</I> Major Section
</h2>
<p>In addition to the inline tag in the heading, this section
defines the term <i>inline</i>, which literally
means
"no line break". It also adds a simple link to the
main page for the Java platform (<a
href="http://java.sun.com">http://java.sun.com</a>),
as well as a link to the
<a href="http://java.sun.com/xml">XML</a> page.
</p>
Хорошая работа! Вы сейчас преобразовали довольно сложный XML-файл в HTML.
(Кажущийся простым на первый взгляд, он определенно предоставил много возможностей
для исследования.)
Web-
Rendered by www.RenderX.com
Стр. 288 из 626 XML Stylesheet Language for Transformations
Web-
Rendered by www.RenderX.com
Преобразование из командной строки Стр. 289 из 626
java org.apache.xalan.xsltc.cmdline.Compile
-o transletName -d directory -j jarFile
-p packageName {-u stylesheetURI | stylesheetFile }
Web-
Rendered by www.RenderX.com
Стр. 290 из 626 XML Stylesheet Language for Transformations
где
• -o transletName
Указывает имя генерируемого класса транслета (выходной класс). Суффикс .class не
обязателен. Если он отсутствует, то автоматически добавляется к имени, указанному
в аргументе stylesheet.
• -d directory
Указывает каталог назначения. (По умолчанию - текущий каталог.)
• -j jarFile
Выводит генерируемые файлы класса транслета в JAR-файл с именем jarFile.jar. При
использовании этого аргумента создается только JAR-файл.
• -p packageName
Указывает имя пакета для генерируемых классов транслета.
• -u stylesheetURI
Указывает таблицу стилей при помощи URI, например http://meserver/stylesheet1.xsl.
• stylesheetFile
(Не флаг) Путь к файлу таблицы стилей.
java org.apache.xalan.xsltc.cmdline.Transform
article3.xml article3
Примечание: Опять установите classpath, как описано в разделе "Компиляция и выполнение
программы", если вы работаете на версии 1.3 платформы Java.
Эта команда добавляет текущий каталог к переменной classpath, для того чтобы транслет
мог быть найден. Вывод осуществляется на System.out.
Ниже приведены возможные аргументы, которые могут быть указаны при запуске транслета:
java org.apache.xalan.xsltc.cmdline.Transform
{-u documentURI | documentFilename}
className [name=value...]
где
• -u documentURI
Указывает URI входного XML-документа.
• documentFilename
Указывает имя файла входного XML-документа.
• className
Транслет, выполняющий преобразование. (Здесь вы не можете указать суффикс .class,
так же как вы пропускаете его при запуске java-приложения.)
Web-
Rendered by www.RenderX.com
Объединение преобразований при помощи цепочки фильтров Стр. 291 из 626
• name=value…
Необязательный набор из одного или более параметров таблицы стилей, указанных в
виде пар имя-значение.
import javax.xml.parsers.FactoryConfigurationError;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;
import org.xml.sax.SAXException;
import org.xml.sax.SAXParseException;
import org.xml.sax.InputSource;
import org.xml.sax.XMLReader;
import org.xml.sax.XMLFilter;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.TransformerConfigurationException;
import javax.xml.transform.sax.SAXTransformerFactory;
import javax.xml.transform.sax.SAXSource;
import javax.xml.transform.sax.SAXResult;
import javax.xml.transform.stream.StreamSource;
import javax.xml.transform.stream.StreamResult;
import java.io.*;
Web-
Rendered by www.RenderX.com
Стр. 292 из 626 XML Stylesheet Language for Transformations
}
catch (TransformerConfigurationException tce) {
// ,
System.out.println ("* Transformer Factory error");
System.out.println(" " + tce.getMessage() );
//
,
Throwable x = tce;
if (tce.getException() != null)
x = tce.getException();
x.printStackTrace();
}
catch (TransformerException te) {
// ,
System.out.println ("* Transformation error");
System.out.println(" " + te.getMessage() );
//
,
Throwable x = te;
if (te.getException() != null)
x = te.getException();
x.printStackTrace();
}
catch (SAXException sxe) {
// ,
Web-
Rendered by www.RenderX.com
Объединение преобразований при помощи цепочки фильтров Стр. 293 из 626
pce.printStackTrace();
}
catch (IOException ioe) {
// I/O
ioe.printStackTrace();
}
Между операторами import и обработчиками ошибок располагается основная часть
программы:
try {
//
File stylesheet1 = new File(argv[0]);
File stylesheet2 = new File(argv[1]);
File datafile = new File(argv[2]);
//
BufferedInputStream bis = new
BufferedInputStream(newFileInputStream(datafile));
InputSource input = new InputSource(bis);
// ( .
#1)
SAXParserFactory spf = SAXParserFactory.newInstance();
spf.setNamespaceAware(true);
SAXParser parser = spf.newSAXParser();
XMLReader reader = parser.getXMLReader();
// ( . #2)
SAXTransformerFactory stf =
(SAXTransformerFactory)
TransformerFactory.newInstance();
Web-
Rendered by www.RenderX.com
Стр. 294 из 626 XML Stylesheet Language for Transformations
// filter1
( . #3)
// filter1 filter2
filter1.setParent(reader);
filter2.setParent(filter1);
//
StreamResult result = new StreamResult(System.out);
//
SAX- ,
//
Web-
Rendered by www.RenderX.com
Объединение преобразований при помощи цепочки фильтров Стр. 295 из 626
Web-
Rendered by www.RenderX.com
Стр. 296 из 626 XML Stylesheet Language for Transformations
<?xml version="1.0"?>
<Article>
<ArtHeader>
<Title>Title of my (Docbook) article</Title>
</ArtHeader>
<Sect1>
<Title>Title of Section 1.</Title>
<Para>This is a paragraph.</Para>
</Sect1>
</Article>
Затем создадим таблицу стилей для преобразования ее в формат ARTICLE:
<xsl:stylesheet
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="1.0"
>
<xsl:output method="xml"/> ( . #1)
<xsl:template match="/">
<ARTICLE>
<xsl:apply-templates/>
</ARTICLE>
</xsl:template>
Web-
Rendered by www.RenderX.com
Объединение преобразований при помощи цепочки фильтров Стр. 297 из 626
<SECT><xsl:apply-templates/></SECT>
</xsl:template>
<xsl:template match="Para">
<PARA><xsl:apply-templates/></PARA> ( .
#5)
</xsl:template>
</xsl:stylesheet>
Примечания:
1. На этот раз таблица стилей генерирует XML-формат.
2. Следующий шаблон (для элемента title самого верхнего уровня) соответствует только
главному заголовку. Для заголовков секций используется тег TITLE. (Поскольку нет
шаблона преобразования, относящегося к этим элементам title, - они игнорируются.
Однако текстовые узлы, которые они содержат, передаются как результат XSLT
встроенных правил шаблонов - то есть игнорируется только тег, а не текст. Более
подробно об этом ниже.)
3. Элемент title из заголовка DocBook становится элементом title ARTICLE.
4. Нумерованные теги секции преобразуются в обычные теги SECT.
5. Этот шаблон выполняет преобразование регистра, то есть Para становится PARA.
Хотя об этом не было сказано отдельно, XSLT определяет несколько встроенных (по
умолчанию) правил шаблонов. Их полный набор перечислен в разделе 5.8 спецификации.
В основном они предназначены для автоматического копирования текстовых узлов и узлов
атрибутов, а также для пропуска комментариев и инструкций обработки. Они, также,
обеспечивают обработку внутренних элементов даже в том случае, когда содержащие их
теги не имеют шаблонов. Это является причиной того, что текстовый узел обрабатывается
в заголовке секции, хотя этот заголовок не описан ни в одном из шаблонов.
Теперь выполните программу FilterChain, передав ей приведенную выше таблицу стилей
(docbookToArticle.xsl), таблицу стилей ARTICLE (article1c.xsl) и небольшой DocBook-файл
(small-docbook-article.xml) в этом порядке. Результат должен выглядеть примерно так:
<html>
<body>
<h1 align="center">Title of my (Docbook) article</h1>
<h2>Title of Section 1.</h2>
<p>This is a paragraph.</p>
</body>
</html>
Примечание: Этот результат был сгенерирован при использовании JAXP 1.0. Однако
первый фильтр в цепочке сейчас не транслирует ни одного тега во входном файле. Пока
этот дефект не будет устранен, результат, который вы увидите, будет состоять из
Web-
Rendered by www.RenderX.com
Стр. 298 из 626 Java API for XML-based RPC
9.8.4. Заключение
Поздравляем! Вы закончили руководство по XSLT. Вы немало поработали с XML и XSLT
и готовы к изучению многих других захватывающих возможностей.
Web-
Rendered by www.RenderX.com
Простой пример: HelloWorld Стр. 299 из 626
Web-
Rendered by www.RenderX.com
Стр. 300 из 626 Java API for XML-based RPC
10.2.3. Настройка
Если вы этого еще не сделали, выполните следующие инструкции в главе "Начало работы
с Tomcat":
• Установка переменной PATH
• Создание и компоновка файла свойств
• Запуск Tomcat
Web-
Rendered by www.RenderX.com
Простой пример: HelloWorld Стр. 301 из 626
package hello;
import java.rmi.Remote;
import java.rmi.RemoteException;
package hello;
Web-
Rendered by www.RenderX.com
Стр. 302 из 626 Java API for XML-based RPC
return message + s;
}
}
ant compile-server
Это команда помещает создающиеся файлы классов в подкаталоге build/shared.
ant setup-web-inf
ant package
Задание setup-web-inf копирует файлы классов и XML-файлы в подкаталог build/WEB-INF.
Задание package выполняет команду jar и группирует файлы в WAR-файл с именем
dist/hello-portable.war. Этот WAR-файл не готов для размещения, поскольку он не содержит
классов узлов. В следующем разделе вы узнаете, как создать WAR-файл, готовый для
размещения. hello-portable.war содержит следующие файлы:
WEB-INF/classes/hello/HelloIF.class
WEB-INF/classes/hello/HelloImpl.class
WEB-INF/jaxrpc-ri.xml
WEB-INF/web.xml
Файлы классов были созданы заданием compile-server, как показано в предыдущем разделе.
Файл web.xml является дескриптором размещения для Web-приложения, реализующего
службу. В отличие от web.xml, файл jaxrpc-ri.xml не является частью спецификации и
зависит от реализации. Файл jaxrpc-ri.xml для данного примера выглядит так:
<endpoint
name="MyHello"
Web-
Rendered by www.RenderX.com
Простой пример: HelloWorld Стр. 303 из 626
displayName="HelloWorld Service"
description="A simple web service"
interface="hello.HelloIF"
implementation="hello.HelloImpl"/>
<endpointMapping
endpointName="MyHello"
urlPattern="/hello"/>
</webServices>
Некоторые из атрибутов webServices, такие как targetNamespaceBase, используются в
WSDL-файле, который вы создадите в следующем разделе. (WSDL-файлы могут быть
сложными и не рассматриваются в данном руководстве. См. раздел "Дополнительная
информация".) Обратите внимание, что значение urlPattern (/hello) является частью URL
службы, и рассматривается в разделе "Верификация размещения").
Дополнительную информацию о синтаксисе файла jaxrpc-ri.xml можно найти в файле XML
Schema: <JWSDP_HOME>/docs/tutorial/examples/jaxrpc/common/jax-rpc-ri-dd.xsd.
ant process-war
Эта команда запускает программу wsdeploy следующим образом:
Web-
Rendered by www.RenderX.com
Стр. 304 из 626 Java API for XML-based RPC
ant deploy
Для повторного размещения выполните ant redeploy, как описано в разделе "Итеративная
разработка".
http://localhost:8080/hello-jaxrpc/hello
Броузер должен отобразить страницу под названием Web Services, которая содержит имя
порта MyHello со статусом ACTIVE. Эта страница также содержит URL к WSDL-файлу
службы.
Часть URL hello-jaxrpc.war является путем контекста сервлета, реализующего службу
HelloWorld. Эта часть соответствует префиксу файла hello-jaxrpc.war. Строка /hello в URL
соответствует значению атрибута urlPattern файла jaxrpc-ri.xml. Обратите внимание, что
прямой слеш в значении /hello в urlPattern необходим. Полный листинг файла jaxrpc-ri.xml
приведен в разделе "Пакетирование WAR-файла".
ant undeploy
Web-
Rendered by www.RenderX.com
Простой пример: HelloWorld Стр. 305 из 626
• Откомпилируйте код.
• Спакетируйте клиентские классы в JAR-файл.
• Запустите клиентскую программу.
Следующие разделы описывают эти шаги более детально.
ant generate-stubs
Эта команда запускает служебную программу wscompile следующим образом:
Web-
Rendered by www.RenderX.com
Стр. 306 из 626 Java API for XML-based RPC
package hello;
import javax.xml.rpc.Stub;
ant compile-client
ant jar-client
Эта команда создает файл dist/hello-client.jar.
Web-
Rendered by www.RenderX.com
Простой пример: HelloWorld Стр. 307 из 626
ant run
Программа должна отобразить следующую строку:
Hello Duke!
Задание ant run выполняет следующую команду:
Web-
Rendered by www.RenderX.com
Стр. 308 из 626 Java API for XML-based RPC
java.lang.Boolean
java.lang.Byte
java.lang.Double
java.lang.Float
java.lang.Integer
java.lang.Long
java.lang.Short
java.lang.String
java.math.BigDecimal
java.math.BigInteger
java.util.Calendar
java.util.Date
Данная редакция JAX-RPC поддерживает также несколько классов реализации интерфейса
java.util.Collection. См. таблицу 9-2.
Таблица 9-2 Поддерживаемые классы коллекций Java
Субинтерфейсы java.util.Collection Классы реализации
List ArrayList
LinkedList
Stack
Vector
Map HashMap
Hashtable
Properties
TreeMap
Web-
Rendered by www.RenderX.com
Типы, поддерживаемые в JAX-RPC Стр. 309 из 626
10.3.2. Примитивы
JAX-RPC поддерживает следующие элементарные типы языка программирования Java:
boolean
byte
double
float
int
long
short
10.3.3. Массивы
JAX-RPC поддерживает также массивы с членами, имеющими поддерживаемые JAX-RPC
типы. Примерами поддерживаемых массивов являются int[] и String[]. Поддерживаются
также многомерные массивы, такие как BigDecimal[][].
Web-
Rendered by www.RenderX.com
Стр. 310 из 626 Java API for XML-based RPC
package proxy;
import java.net.URL;
import javax.xml.rpc.Service;
import javax.xml.rpc.JAXRPCException;
import javax.xml.namespace.QName;
import javax.xml.rpc.ServiceFactory;
String UrlString =
"http://localhost:8080/ProxyHelloWorld.wsdl";
String nameSpaceUri = "http://proxy.org/wsdl";
String serviceName = "HelloWorld";
String portName = "HelloIFPort";
ServiceFactory serviceFactory =
ServiceFactory.newInstance();
Service helloService =
serviceFactory.createService(helloWsdlUrl,
new QName(nameSpaceUri, serviceName));
Web-
Rendered by www.RenderX.com
Пример клиентской программы Dynamic Invocation Interface (DII) Стр. 311 из 626
System.out.println(myProxy.sayHello("Buzz"));
Web-
Rendered by www.RenderX.com
Стр. 312 из 626 Java API for XML-based RPC
package dynamic;
import javax.xml.rpc.Call;
import javax.xml.rpc.Service;
import javax.xml.rpc.JAXRPCException;
import javax.xml.namespace.QName;
import javax.xml.rpc.ServiceFactory;
import javax.xml.rpc.ParameterMode;
ServiceFactory factory =
ServiceFactory.newInstance();
Service service =
factory.createService(new QName(qnameService));
Web-
Rendered by www.RenderX.com
Пример клиентской программы Dynamic Invocation Interface (DII) Стр. 313 из 626
call.setProperty(Call.SOAPACTION_USE_PROPERTY,
new Boolean(true));
call.setProperty(Call.SOAPACTION_URI_PROPERTY,"");
call.setProperty(ENCODING_STYLE_PROPERTY,
URI_ENCODING);
QName QNAME_TYPE_STRING =
new QName(NS_XSD, "string");
call.setReturnType(QNAME_TYPE_STRING);
call.setOperationName(
new QName(BODY_NAMESPACE_VALUE "sayHello"));
call.addParameter("String_1", QNAME_TYPE_STRING,
ParameterMode.IN);
String[] params = { "Duke!" };
ant build
ant deploy
ant build-dynamic
ant run
Должна отобразиться следующая строка:
Web-
Rendered by www.RenderX.com
Стр. 314 из 626 Java API for XML-based RPC
Web-
Rendered by www.RenderX.com
Безопасность в JAX-RPC Стр. 315 из 626
имя сервера в ответ на первый запрос, который спросит имя и фамилию. Введите
следующее:
Web-
Rendered by www.RenderX.com
Стр. 316 из 626 Java API for XML-based RPC
2. Перезапустите Tomcat.
3. Убедитесь, что SSL-коннектор был добавлен, следуя указаниям раздела "Верификация
SSL-поддержки".
<security-constraint>
<web-resource-collection>
<web-resource-name>SecureHello</web-resource-name>
<url-pattern>/security</url-pattern>
<http-method>GET</http-method>
<http-method>POST</http-method>
</web-resource-collection>
<auth-constraint>
<role-name>manager</role-name>
</auth-constraint>
</security-constraint>
<login-config>
<auth-method>BASIC</auth-method>
</login-config>
Обратите внимание, что элемент <role-name> указывает manager, роль, которая уже была
указана в файле <JWSDP_HOME>/conf/tomcat-users.xml. Чтобы узнать, как обновить файл
tomcat-users.xml при помощи admintool, обратитесь к разделу "Управление ролями".
Web-
Rendered by www.RenderX.com
Безопасность в JAX-RPC Стр. 317 из 626
<JWSDP_HOME>/docs/tutorial/examples/jaxrpc/security/client.key
store
В предыдущем разделе "Генерирование сертификатов для базовой аутентификации" вы
создали файл client.keystore при помощи выполнения программы keytool. Клиент указывает
свойство trustStore следующим образом:
System.setProperty("javax.net.ssl.trustStore", trustStore);
System.setProperty("javax.net.ssl.trustStorePassword",
trustStorePassword);
stub._setProperty(javax.xml.rpc.Stub.USERNAME_PROPERTY,
username);
stub._setProperty(javax.xml.rpc.Stub.PASSWORD_PROPERTY,
password);
Web-
Rendered by www.RenderX.com
Стр. 318 из 626 Java API for XML-based RPC
ant build
ant deploy
ant build-static
ant run-security
Должна отобразиться следующая строка:
ant run-security
Должна отобразиться следующая строка:
Web-
Rendered by www.RenderX.com
JAX-RPC в J2EE SDK 1.3.1 Стр. 319 из 626
http://java.sun.com/j2ee/tutorial/index.html
Для выполнения этого примера вы должны загрузить и установить J2EE SDK, который
доступен по следующему URL:
http://java.sun.com/j2ee/sdk_1.3/index.html
Примечание: На странице предыдущего URL обязательно прочитайте раздел
"Поддерживаемые операционные системы и необходимое программное обеспечение".
J2EE SDK не поддерживает Windows 95, 98, ME или XP.
System.out.println(stub.sayHello("Buzz!"));
Затем, метод sayHello класса HelloImpl вызывает метод sayHey компонента GreetingEJB:
try {
Context initial = new InitialContext();
Context myEnv =
(Context)initial.lookup("java:comp/env");
Object objref = myEnv.lookup("ejb/SimpleGreeting");
Web-
Rendered by www.RenderX.com
Стр. 320 из 626 Java API for XML-based RPC
GreetingHome home =
(GreetingHome)PortableRemoteObject.narrow
(objref, GreetingHome.class);
return result;
}
Вот метод sayHey класса GreetingBean не имеющего состояния сессионного компонента
GreetingEJB:
ant build
ant build-static
Эти команды создадут файлы toejb-jaxrpc.war и toejb-client.jar в подкаталоге dist.
Web-
Rendered by www.RenderX.com
JAX-RPC в J2EE SDK 1.3.1 Стр. 321 из 626
<JWSDP_HOME>/bin/jwsdponj2ee.sh $J2EE_HOME
Windows:
<JWSDP_HOME>\bin\jwsdponj2ee.bat %J2EE_HOME%
Сценарий jwsdponj2ee добавляет библиотеки Java WSDP к J2EE SDK и затем меняет
порт Web-службы J2EE SDK с 8000 в 8080. После завершения выполнения этого
примера вы, возможно, захотите выполнить инструкции раздела "Удаление действий
jwsdponj2ee".
5. В терминальном окне запустите j2ee-сервер:
j2ee -verbose
6. И Java WSDP, и J2EE SDK имеют служебные программы, называемые deploytool. Для
следующих действий вы должны запускать deploytool из J2EE SDK. Для проверки того,
что ваша переменная окружения PATH указывает на deploytool из J2EE SDK, выполните
следующую команду:
deploytool -version
Программа должна отобразить следующую строку:
deploytool
Web-
Rendered by www.RenderX.com
Стр. 322 из 626 Java API for XML-based RPC
ant run
Должна отобразиться следующая строка:
Hey Buzz!!
Web-
Rendered by www.RenderX.com
Создание службы JAX-RPC в deploytool Стр. 323 из 626
ant build
Задание build выполняет следующие задачи:
• Компилирует интерфейс службы и класс реализации
• Компилирует клиентское приложение
• Пакетирует клиентское приложение в файл dist/dephello-client.jar
Web-
Rendered by www.RenderX.com
Стр. 324 из 626 Java API for XML-based RPC
<JWSDP_HOME>/docs/tutorial/examples/jaxrpc/dephello/build/shared.
B. Добавьте HelloIF.class и HelloImpl.class в поле Contents of MyHelloWAR.
C. Нажмите OK.
D. Нажмите Next.
http://wombat.com/wsdl/
B. В поле Schema Target Namespace Base String введите следующее:
http://wombat.com/xsd/
C. В поле Endpoint Alias Base String введите /jaxrpc.
D. Нажмите Next.
Web-
Rendered by www.RenderX.com
Создание службы JAX-RPC в deploytool Стр. 325 из 626
http://localhost:8080/jaxrpc-dephello/jaxrpc/MyHelloWorld
В броузере отобразится страница, показывающая статус имени порта (или конечной точки)
MyHelloWorld. Эта страница также показывает URL для WSDL-документа:
http://localhost:8080/jaxrpc-dephello/jaxrpc/MyHelloWorld?WSDL
Этот URL программа HelloClient будет использовать для определения WSDL-документа,
созданного во время размещения.
Web-
Rendered by www.RenderX.com
Стр. 326 из 626 Java API for XML Messaging
Примечание: Если у вас возникли проблемы при размещении Web-службы, может быть
полезным сравнение вашего файла MyHello.war с файлом CompareMyHello.war из
подкаталога dephello/provided-jars.
ant run
На клиентском компьютере должна отобразиться следующая строка:
Web-
Rendered by www.RenderX.com
Введение в JAXM Стр. 327 из 626
11.1.1. Сообщения
JAXM-сообщения соответствуют стандарту SOAP, который описывает формат сообщений,
а также указывает обязательные, не обязательные и недопустимые элементы. При помощи
JAXM API вы можете создавать XML-сообщения, соответствующие спецификациям SOAP,
простым вызовом Java API.
Web-
Rendered by www.RenderX.com
Стр. 328 из 626 Java API for XML Messaging
Web-
Rendered by www.RenderX.com
Введение в JAXM Стр. 329 из 626
Web-
Rendered by www.RenderX.com
Стр. 330 из 626 Java API for XML Messaging
SAAJ API предоставляет класс AttachmentPart для представления части вложения SOAP-
сообщения. Объект SOAPMessage автоматически содержит объект SOAPPart и его
необходимые подчиненные элементы, но поскольку объект AttachmentPart не обязателен,
вы должны создать и добавить его самостоятельно. Раздел "Учебник" покажет вам процесс
создания и заполнения сообщений с вложениями и без них.
Объект SOAPMessage может иметь одно или более вложений. Каждый объект Attachment-
Part имеет MIME-заголовок для обозначения типа содержащихся в нем данных. Он может
также содержать дополнительные MIME-заголовки для обозначения типа или для указания
месторасположения, которые могут быть полезны при наличии нескольких вложений. Когда
объект SOAPMessage имеет один или более объектов AttachmentPart, его объект SOAPPart
может иметь содержимое сообщения, а может и не иметь.
На систему обмена сообщениями SOAP можно взглянуть еще с одной стороны. А именно
- используется или нет поставщик службы обмена сообщениями. Этот вопрос обсуждается
в разделе "Поставщики службы обмена сообщениями".
Web-
Rendered by www.RenderX.com
Введение в JAXM Стр. 331 из 626
11.1.2. Соединения
Все SOAP-сообщения передаются и принимаются по соединению. Соединение может быть
установлено непосредственно с конкретным адресатом, или с поставщиком службы обмена
сообщениями. (Поставщик службы обмена сообщениями представляет собой службу,
которая управляет передачей и маршрутизацией сообщений и предоставляет возможности,
недоступные при использовании соединения непосредственно с конечным адресатом.
Поставщики службы обмена сообщениями рассмотрены более детально далее.)
JAXM API предоставляет следующие классы и интерфейсы для представления этих двух
типов соединений:
1. javax.xml.soap.SOAPConnection - соединение между отправителем и непосредственно
с адресатом (соединение точка-точка).
2. javax.xml.mesaging.ProviderConnection - соединение с поставщиком службы обмена
сообщениями.
11.1.2.1. SOAPConnection
Объект SOAPConnection, представляющий соединение точка-точка, создать и использовать
просто. Одна из причин этого - вы не должны выполнять какую-либо настройку для
использования объекта SOAPConnection, поскольку он не должен работать в контейнере
сервлетов (например Tomcat) или в J2EE-контейнере. Он является единственным типом
соединения, доступным клиенту, не использующему поставщика службы обмена
сообщениями.
В следующем фрагменте кода создается объект SOAPConection и, затем, после создания
и заполнения сообщения, используется соединение для передачи сообщения. Параметр
request представляет собой передаваемое сообщение, а endpoint - пункт назначения.
SOAPConnectionFactory factory =
SOAPConnectionFactory.newInstance();
SOAPConnection con = factory.createConnection();
. . .// request
Web-
Rendered by www.RenderX.com
Стр. 332 из 626 Java API for XML Messaging
11.1.2.2. ProviderConnection
Объект ProviderConnection представляет соединение с поставщиком службы обмена
сообщениями. (В следующем разделе поставщики службы обмена сообщениями
рассматриваются более подробно.) При передаче сообщения через объект ProviderCon-
nection, оно приходит поставщику службы обмена сообщениями. Поставщик службы обмена
сообщениями перенаправит это сообщение указанному адресату и затем возвратит ответ
при его наличии. Интервал между передачей запроса и получением ответа может быть
очень коротким, а может измеряться днями. При таком типе обмена сообщениями
оригинальное сообщение передается как однонаправленное сообщение, и любой ответ
передается позже как однонаправленное сообщение. Не удивительно, что этот тип обмена
сообщениями называется однонаправленным.
Web-
Rendered by www.RenderX.com
Введение в JAXM Стр. 333 из 626
11.1.3.1. Прозрачность
Одним из основных преимуществ поставщика службы обмена сообщениями является то,
что вы даже не замечаете его. Вы просто пишете ваше JAXM-приложение, а все остальное
произойдет само. Например, при использовании поставщика службы обмена сообщениями
и передаче сообщения при помощи вызова метода ProviderConnection.send, этот поставщик
принимает сообщение и работает с другими частями коммуникационной инфраструктуры
для выполнения различных задач в зависимости от содержимого заголовка сообщения и
реализации службы поставщика. Сообщение прибывает к конечному адресату без знания
вами деталей процесса доставки.
11.1.3.2. Профили
JAXM предоставляет возможность подключать дополнительные протоколы, построенные
на верхнем уровне SOAP. От реализации поставщика JAXM не требуется поддержка
функциональности, выходящей за рамки требований спецификаций SOAP 1.1 и SOAP with
Attachments. Но этой реализации разрешено поддерживать другие стандартные протоколы,
называемые профилями, которые строятся на верхнем уровне SOAP. Например,
спецификация "ebXML Message Service Specification" (доступная на http://www.oasis-
open.org/committees/ebxml-msg/) определяет уровни службы, не включенные в спецификации
SOAP. О поставщике службы обмена сообщениями, который включает возможности ebXML
на верхнем уровне SOAP, говорят, что он поддерживает ebXML-профиль. Поставщик
службы обмена сообщениями может поддерживать несколько профилей, но приложение
может использовать только один в данный момент времени, и нужно иметь предварительное
соглашение с каждым из участников, которому передаются сообщения, об используемом
профиле.
Профили влияют на заголовки сообщения. Например, в зависимости от профиля, новый
объект SOAPMessage создается с определенными, уже установленными заголовками.
Также, реализация профиля может предоставить API, облегчающие создание заголовка
и установку его содержимого. Справочная реализация JAXM включает API и для профиля
ebXML, и для профиля SOAP-RP. Документация для этих профилей в формате Javadoc
находится на странице <JWSDP_HOME>/docs/jaxm/profiles/index.html. Ссылки на Javadoc-
документацию по JAXM API (javax.xml.soap и javax.xml.messaging) находятся на странице
<JWSDP_HOME>/docs/api/index.html.
Web-
Rendered by www.RenderX.com
Стр. 334 из 626 Java API for XML Messaging
Web-
Rendered by www.RenderX.com
Выполнение примеров Стр. 335 из 626
http://localhost:8080/index.html
2. На появившейся странице нажмите на один из перечисленных примеров приложений.
Затем следуйте инструкциям в новом окне.
Web-
Rendered by www.RenderX.com
Стр. 336 из 626 Java API for XML Messaging
Web-
Rendered by www.RenderX.com
Учебник Стр. 337 из 626
<JWSDP_HOME>/docs/tutorial/examples/jaxm/samples/
Вы найдете шесть подкаталогов, по одному на каждый пример, выполняющийся в Tomcat.
Подкаталог jaxmtags содержит несколько .jsp-файлов. Другие подкаталоги содержат два
файла SendingServlet.java и ReceivingServlet.java. Кроме этих двух файлов подкаталог
translator содержит файл TranslationSevice.java.
Если вы хотите увидеть все файлы, которые составляют Web-приложение, вы можете
перейти в каталог <JWSDP_HOME>/webapps и распаковать .war-файлы. Например, для
примера Simple вы должны сделать следующее:
cd <JWSDP_HOME>/webapps
jar -xvf jaxm-simple.war
Кроме исходных файлов и файлов классов для примера Simple вы найдете файлы web.xml
и build.xml.
Файл web.xml, называемый дескриптором размещения, связывает конечную точку,
переданную в метод SOAPConnection.call или ProviderConnection.Send с конкретным
классом сервлета. Когда контейнер встречает конечную точку, являющуюся обычно URI,
он использует файл web.xml для определения соответствующего класса сервлета и его
выполнения. Пример и объяснение этого процесса находится в конце раздела "Передача
запроса".
Файл build.xml является файлом для программы ant, используемым при запуске приложения.
11.3. Учебник
В этом разделе рассмотрены основы передачи SOAP-сообщения с помощью JAXM API.
К концу этой главы вы узнаете, как выполнить следующее:
• Получить соединение
Web-
Rendered by www.RenderX.com
Стр. 338 из 626 Java API for XML Messaging
• Создать сообщение
• Добавить содержимое в сообщение
• Передать сообщение
• Извлечь содержимое из ответного сообщения
• Создать и извлечь элемент SOAP-ошибки
Прежде всего, мы выполним действия для передачи сообщения типа запрос-ответ для
клиента, не использующего поставщика службы обмена сообщениями. Затем мы исследуем
клиентское приложение, использующее поставщика службы обмена сообщениями для
передачи однонаправленного сообщения. Оба типа клиентов могут добавить в сообщения
вложения, поэтому добавление вложений выделено в отдельную тему. Наконец, вы узнаете,
что такое SOAP-ошибки и как с ними работать.
Раздел "Примеры кода" содержит фрагменты кода, которые вы будете использовать в
исполняемых приложениях и сможете протестировать самостоятельно. JAXM-часть
исследования ("JAXM-служба распределения") демонстрирует использование JAXM-кода
в Web-службе, показывая код клиента и сервера.
SOAPConnectionFactory scFactory =
SOAPConnectionFactory.newInstance();
Обратите внимание, что поскольку newInstance является статическим методом, вы всегда
будете использовать имя класса SOAPConnectionFactory при вызове его метода newInstance.
Теперь вы можете использовать scFactory для создания объекта SOAPConnection.
Web-
Rendered by www.RenderX.com
Учебник Стр. 339 из 626
Web-
Rendered by www.RenderX.com
Стр. 340 из 626 Java API for XML Messaging
header.detachNode();
Web-
Rendered by www.RenderX.com
Учебник Стр. 341 из 626
""m"", ""http://wombat.ztrade.com"");
SOAPBodyElement gltp = body.addBodyElement(bodyName);
С этого момента body содержит объект SOAPBodyElement, идентифицируемый объектом
Name bodyName, но содержимого в gltp все еще нет. Предположим, что вы хотите получить
котировки акций Sun Microsystems, Inc. Вы должны создать дочерний элемент для символа,
используя метод addChildElement. Затем необходимо получить символ акции при помощи
метода addTextNode. Объект Name для нового объекта SOAPElement symbol
инициализируется только с локальным именем, которое допустимо для дочерних элементов.
<SOAP-ENV:Envelope
xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"
<SOAP-ENV:Body>
<m:GetLastTradePrice xmlns:m=
"http://wombat.ztrade.com">
<symbol>SUNW</symbol>
</m:GetLastTradePrice>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
Давайте проанализируем этот XML-фрагмент строка за строкой, для того чтобы увидеть,
как он связан с вашим JAXM-кодом. Отметим, что XML-анализатор не обращает внимания
на табуляцию, но она обычно используется для указания уровня элементов и облегчения,
таким образом, чтения кода человеком.
JAXM-код:
Web-
Rendered by www.RenderX.com
Стр. 342 из 626 Java API for XML Messaging
<SOAP-ENV:Envelope
xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"
. . . . . . (intervening elements omitted)
</SOAP-ENV:Envelope>
Самый внешний элемент в этом примере XML является элементом SOAP-конверта,
указанным SOAP-ENV:Envelope. Envelope является именем элемента, а SOAP-ENV -
префиксом пространства имен. Интерфейс SOAPEnvelope представляет SOAP-конверт.
Первая строка сигнализирует о начале элемента SOAP-конверта, а последняя строка
сигнализирует о его конце; все, что внутри - это часть SOAP-конверта. Вторая строка
содержит атрибут для элемента SOAP-конверта. xmlns обозначает "XML namespace"
(пространство имен XML) и его значение - это URI пространства имен, связанного с Enve-
lope. Этот атрибут включается автоматически.
JAXM-код:
<SOAP-ENV:Body>
. . . . . .
</SOAP-ENV:Body>
Эти две строки отмечают начало и конец SOAP-тела, представленного в JAXM объектом
SOAPBody.
JAXM-код:
<m:GetLastTradePrice xmlns:m=
"http://wombat.ztrade.com">
. . . .
</m:GetLastTradePrice>
Эти две строки отображают то, что в вашем коде представляет SOAPBodyElement gltp.
"GetLastTradePrice" - это его локальное имя, "m" - префикс пространства имен,
"http://wombat.ztrade.com" - это его URI пространства имен.
Web-
Rendered by www.RenderX.com
Учебник Стр. 343 из 626
JAXM-код:
<symbol>SUNW</symbol>
Строка "SUNW" - это содержимое сообщения, которое принимает ваш адресат - служба
котировок акций.
con.close();
Web-
Rendered by www.RenderX.com
Стр. 344 из 626 Java API for XML Messaging
SOAPPart sp = response.getSOAPPart();
SOAPEnvelope env = sp.getEnvelope();
SOAPBody sb = env.getBody();
java.util.Iterator it = sb.getChildElements(bodyName);
SOAPBodyElement bodyElement = (SOAPBodyElement)it.next();
String lastPrice = bodyElement.getValue();
System.out.print("The last price for SUNW is ");
System.out.println(lastPrice);
Если бы существовало больше одного элемента с именем bodyElement, вы должны были
бы использовать цикл while и метод Iterator.hasNext для перебора их всех.
while (it.hasNext()) {
SOAPBodyElement bodyElement = (SOAPBodyElement)it.next();
String lastPrice = bodyElement.getValue();
System.out.print("The last price for SUNW is ");
System.out.println(lastPrice);
}
Вы узнали, как передавать сообщение типа запрос-ответ в автономном клиенте. Вы, также,
узнали, как получить содержимое из ответа. Следующий раздел покажет вам, как передать
сообщение, используя поставщика службы обмена сообщениями.
Web-
Rendered by www.RenderX.com
Учебник Стр. 345 из 626
Web-
Rendered by www.RenderX.com
Стр. 346 из 626 Java API for XML Messaging
message.setSender(new Party("http://grand.products.com"));
message.setReceiver(new Party("http://whiz.gizmos.com"));
Вы можете посмотреть комментарии в формате Javadoc по реализациям профилей ebXML
и SOAP-RP, предоставленные в Java WSDP, в следующем каталоге:
<JWSDP_HOME>/docs/jaxm/profile/com/sun/xml/messaging/
Если вы не используете профиль или хотите установить содержимое заголовка, не
обеспечиваемое реализацией профиля, вы должны следовать инструкциям следующего
раздела.
Web-
Rendered by www.RenderX.com
Учебник Стр. 347 из 626
headerElement.addTextNode("order");
Теперь вы имеете объект SOAPHeader header, содержащий объект SOAPHeaderElement,
содержимым которого является слово "order".
Web-
Rendered by www.RenderX.com
Стр. 348 из 626 Java API for XML Messaging
childName = envelope.createName("Product");
SOAPElement product = order.addChildElement(childName);
product.addTextNode("Apple");
childName = envelope.createName("Price");
SOAPElement price = order.addChildElement(childName);
price.addTextNode("1.56");
childName = envelope.createName("Order");
SOAPElement order2 =
purchaseLineItems.addChildElement(childName);
childName = envelope.createName("Product");
SOAPElement product2 = order2.addChildElement(childName);
product2.addTextNode("Peach");
childName = envelope.createName("Price");
SOAPElement price2 = order2.addChildElement(childName);
price2.addTextNode("1.48");
JAXM-код в предыдущем примере генерирует следующий XML в SOAP-теле:
<PO:PurchaseLineItems
xmlns:PO="http://www.sonata.fruitsgalore/order">
<Order>
<Product>Apple</Product>
<Price>1.56</Price>
</Order>
<Order>
<Product>Peach</Product>
<Price>1.48</Price>
</Order>
</PO:PurchaseLineItems>
Web-
Rendered by www.RenderX.com
Учебник Стр. 349 из 626
Web-
Rendered by www.RenderX.com
Стр. 350 из 626 Java API for XML Messaging
pcCon.send(message);
pcCon.close();
Web-
Rendered by www.RenderX.com
Учебник Стр. 351 из 626
attachment.setContent(stringContent, "text/plain");
attachment.setContentId("update_address");
message.addAttachmentPart(attachment);
Переменная attachment теперь представляет объект AttachmentPart, который содержит
String stringContent и имеет заголовок, содержащий String "text/plain". Он также имеет
заголовок Content-Id со значением "update_address". И сейчас attachment является частью
message.
Предположим, что вы хотите вложить jpeg-изображение, показывающее, как красива новая
местность. В этом случае второй аргумент, переданный в setContent, должен быть равен
"image/jpeg" для соответствия добавляемому содержимому. Код для добавления
изображения может выглядеть примерно так, как показано ниже. Для первого вложения
Object, переданный в метод setContent, имел тип String. В данном случае, это - stream.
byte[] jpegData = . . .;
ByteArrayInputStream stream = new ByteArrayInputStream(
jpegData);
attachment2.setContent(stream, "image/jpeg");
message.addAttachmentPart(attachment);
Два других метода SOAPMessage.createAttachment создают объект AttachmentPart с
содержимым. Один очень похож на метод AttachmentPart.setContent в том, что принимает
такие же параметры и делает по существу то же самое. Он принимает Java Object с
содержимым и String с его типом. Как и в AttachmentPart.setContent, Object может быть
объектами String, stream, javax.xml.Transform.Source или javax.activation.DataHandler. Вы
уже видели пример использования объекта Source в качестве содержимого. Следующий
пример покажет использование объекта DataHandler для содержимого.
Другой метод создания объекта AttachmentPart с содержимым принимает объект DataHan-
dler, являющийся частью JavaBeans™ Activation Framework (JAF). Использовать объект
DataHandler довольно просто. Сначала вы создаете объект java.net.URL для файла, который
вы хотите добавить как содержимое. Затем создаете объект DataHandler,
инициализированный объектом URL, и передаете его в метод createAttachmentPart.
message.addAttachmentPart(attachment);
Web-
Rendered by www.RenderX.com
Стр. 352 из 626 Java API for XML Messaging
java.util.Iterator it = message.getAttachments();
while (it.hasNext()) {
AttachmentPart attachment = (AttachmentPart)it.next();
Object content = attachment.getContent();
String id = attachment.getContentId();
System.out.print("Attachment " + id + " contains: " +
content);
System.out.println("");
}
11.3.3.3. Резюме
В этом разделе вы познакомились с основами JAXM API. Вы узнали, как создавать и
передавать SOAP-сообщения в автономном клиенте и в клиенте, использующем поставщика
службы обмена сообщениями. Вы рассмотрели процесс добавления содержимого в
заголовок и тело SOAP-сообщения, а также рассмотрели процесс создания вложений и
добавления в них содержимого. Кроме того, вы узнали, как извлечь содержимое из SOAP-
части и из вложений. Другими словами, вы рассмотрели использование основных
возможностей JAXM API.
11.3.4.1. Обзор
Если вы передаете сообщение, которое по каким-либо причинам не является правильным,
вы можете получить ответ, содержащий элемент SOAP-ошибки, который передает вам
информацию о статусе, информацию об ошибке, или и то и другое. Может быть только
один элемент SOAP-ошибки в сообщении, и он должен быть записью в теле SOAP-
сообщения. Спецификация SOAP 1.1 определяет только одну запись в теле, которая
является элементом SOAP-ошибки. Естественно, тело SOAP-сообщения может содержать
другие записи, но элемент SOAP-ошибки является единственным определенным.
Web-
Rendered by www.RenderX.com
Учебник Стр. 353 из 626
Web-
Rendered by www.RenderX.com
Стр. 354 из 626 Java API for XML Messaging
SOAPEnvelope envelope =
msg.getSOAPPart().getEnvelope();
SOAPBody body = envelope.getBody();
Имея объект SOAPBody body, вы можете использовать его для создания объекта SOAPFault
при помощи следующей строки кода:
fault.setFaultCode("Server");
fault.setFaultActor("http://gizmos.com/orders");
fault.setFaultString("Server not responding");
Объект SOAPFault fault, созданный в предыдущих строках кода, указывает, что причиной
проблемы является недоступность сервера и что актер в "http://gizmos.com/orders" имеет
проблемы. Если бы сообщение было направлено только к конечному адресату, не было
бы необходимости устанавливать актера ошибки. Также обратите внимание, что fault не
имеет объекта Detail, поскольку ошибка не относится к объекту SOAPBody.
В следующем фрагменте кода создается объект SOAPFault, включающий объект Detail.
Обратите внимание, что объект SOAPFault может иметь только один объект Detail, который
является простым контейнером объектов DetailEntry, но объект Detail может иметь несколько
объектов DetailEntry. Объект Detail в следующих строках кода имеет два объекта
DetailEntry, добавленных к нему.
fault.setFaultCode("Client");
fault.setFaultString("Message does not have necessary info");
Web-
Rendered by www.RenderX.com
Учебник Стр. 355 из 626
SOAPBody body =
newmsg.getSOAPPart().getEnvelope().getBody();
if ( body.hasFault() ) {
SOAPFault newFault = body.getFault();
String code = newFault.getFaultCode();
String string = newFault.getFaultString();
String actor = newFault.getFaultActor();
В следующем коде полученные значения распечатываются. Актер ошибки может
присутствовать не во всех сообщениях, поэтому в коде проверяется его наличие. Проверка
того, не равна ли переменная actor значению null, возможна потому, что метод getFaultActor
возвращает null, если актер не был установлен.
if ( actor != null ) {
System.out.println(" fault actor = " + actor);
Web-
Rendered by www.RenderX.com
Стр. 356 из 626 Java API for XML Messaging
}
}
Последней задачей является извлечение объекта Detail и его объектов DetailEntry. В коде
используется объект SOAPFault newFault для извлечения объекта Detail newDetail, а затем
используется newDetail для вызова метода getDetailEntries. Этот метод возвращает объект
java.util.Iterator it, который содержит все объекты DetailEntry в newDetail. Объект Detail не
должен быть во всех объектах SOAPDetail, поэтому в коде проверяется, равно ли newDetail
значению null. Если нет, в коде распечатываются значения объекта (объектов) DetailEntry.
11.4.1. Request.java
Класс Request.java объединяет вместе фрагменты кода, используемые в разделе "Клиент,
не использующий поставщика службы обмена сообщениями", и добавляет все, что
необходимо для создания законченного примера клиента, передающего сообщения типа
запрос-ответ. Кроме объединения кода в него добавлены операторы import, метод main и
блок try/catch с обработкой исключительных ситуаций. Файл Request.java, показанный
Web-
Rendered by www.RenderX.com
Примеры приложений Стр. 357 из 626
здесь полностью, является автономным клиентом, который использует SAAJ API (пакет
javax.xml.soap). Нет необходимости использовать пакет javax.xml.messaging, поскольку
приложение не использует поставщика службы обмена сообщениями.
import javax.xml.soap.*;
import java.util.*;
import java.net.URL;
MessageFactory factory =
MessageFactory.newInstance();
SOAPMessage message = factory.createMessage();
con.close();
SOAPPart sp = response.getSOAPPart();
Web-
Rendered by www.RenderX.com
Стр. 358 из 626 Java API for XML Messaging
SOAPEnvelope se = sp.getEnvelope();
SOAPBody sb = se.getBody();
Iterator it = sb.getChildElements(bodyName);
SOAPBodyElement bodyElement =
(SOAPBodyElement)it.next();
String lastPrice = bodyElement.getValue();
Web-
Rendered by www.RenderX.com
Примеры приложений Стр. 359 из 626
cd <JWSDP_HOME>/samples/jaxm/uddiping
run.sh uddi.properties Microsoft
Windows:
cd <JWSDP_HOME>\samples\jaxm\uddiping
run.bat uddi.properties Microsoft
На вашем экране отобразится примерно следующая информация:
Received replyfrom:
http://www3.ibm.com/services/uddi/testregistry/inquiryapi<?xml
version="1.0" encoding="UTF-8" ?><Envelope
xmlns="http://schemas.xmlsoap.org/soap/envelope/"><Body><busin
essList generic="1.0" xmlns="urn:uddi-org:api"
operator="www.ibm.com/services/uddi"
truncated="false"><businessInfos><businessInfo
businessKey="D7475060-BF58-11D5-A432-
0004AC49CC1E"><name>Microsoft Corporation</name><description
xml:lang="en">Computer Software and Hardware
Manufacturer</description><serviceInfos></serviceInfos></busin
essInfo></businessInfos></businessList></Body></Envelope>
Если указанное вами название субъекта бизнеса есть в тестовом реестре, распечатается
XML-документ с именем и описанием этого субъекта бизнеса. Однако они будут встроены
в XML-документ, что затрудняет их просмотр. В следующем разделе в программу UddiP-
ing.java добавляется код, извлекающий содержимое для облегчения просмотра.
Web-
Rendered by www.RenderX.com
Стр. 360 из 626 Java API for XML Messaging
11.4.2.1.1. Настройка
Поскольку имя нового файла - MyUddiPing, создайте каталог myuddiping в каталоге
<JWSDP_HOME>/samples/jaxm.
cd <JWSDP_HOME>/samples/jaxm
mkdir myuddiping
Этот новый каталог myuddiping будет основным каталогом для всех последующих команд,
относящихся к приложению MyUddiPing.java.
Вместо сценариев run.sh или run.bat, использовавшихся для запуска UddiPing, вы будете
использовать файл для программы ant - build.xml для настройки каталогов и файлов и для
запуска MyUddiPing. Преимущество использования файла Ant состоит в том, что он является
платформно-независимым и, следовательно, может применяться и для платформ Unix, и
для Windows. Таким образом, вы должны скопировать файл build.xml в каталог exam-
ples/jaxm руководства в ваш новый каталог myuddiping. (Команда для копирования должна
быть в одной строке. Обратите внимание, что нет пробела между "myuddiping/" и "build",
а также есть символ "." в конце командной строки.
Unix:
cd myuddiping
cp <JWSDP_HOME>/docs/tutorial/examples/jaxm/myuddiping/
build.xml .
Windows:
cd myuddiping
copy <JWSDP_HOME>\docs\tutorial\examples\jaxm\myuddiping\
build.xml .
Как только вы имеете файл build.xml в вашем каталоге myuddiping, вы можете вызвать его
для выполнения остальной работы по настройке и для запуска MyUddiPing. Файл компоновки
для ant является XML-файлом, разделенным на задания, каждое из которых является
элементом, содержащим атрибуты и одну или более задач. Например, элемент задания
с именем атрибута prepare создает каталоги build и src и копирует файл MyUddiPing.java
из каталога <JWSDP_HOME>/docs/tutorial/examples/jaxm/myuddiping/src в новый каталог
src. Затем он копирует файл uddi.properties из каталога uddiping в созданный вами каталог
myuddiping.
Чтобы выполнить эти задачи, введите в командной строке:
ant prepare
Задание, называемое build, компилирует исходный файл MyUddiPing.java и помещает
.class файл результата в build каталог. Чтобы выполнить эти задачи, введите в командной
строке:
Web-
Rendered by www.RenderX.com
Примеры приложений Стр. 361 из 626
ant build
Теперь, когда вы выполнили все настройки, рассмотрим детальнее код программы.
import javax.xml.soap.*;
import javax.xml.messaging.*;
import java.util.*;
import java.io.*;
Следующие несколько строк начинают определение класса MyUddiPing, а именно,
определение метода main. Первое выполняемое действие - проверка наличия двух
аргументов. Если они отсутствуют, программа выводит сообщение о правилах
использования и завершает работу.
Web-
Rendered by www.RenderX.com
Стр. 362 из 626 Java API for XML Messaging
SOAPConnectionFactory scf =
SOAPConnectionFactory.newInstance();
SOAPConnection connection =
scf.createConnection();
MessageFactory msgFactory =
MessageFactory.newInstance();
SOAPMessage msg = msgFactory.createMessage();
В новый объект SOAPMessage msg автоматически включается объект SOAPPart, который
содержит объект SOAPEnvelope. Объект SOAPEnvelope содержит объект SOAPBody,
являющийся элементом, в который мы хотим добавить содержимое. В следующих строках
кода мы получаем объект SOAPPart, объект SOAPEnvelope и объект SOAPBody.
SOAPEnvelope envelope =
msg.getSOAPPart().getEnvelope();
SOAPBody body = envelope.getBody();
В следующих строках добавляется элемент с полностью указанным именем, и в него
добавляются два атрибута. Первый атрибут называется "generic" и имеет значение "1.0".
Второй аргумент называется "maxRows" и имеет значение "100". Затем добавляется
дочерний элемент с именем name, и в него добавляется некоторый текст при помощи
метода addTextNode. Добавляемый текст является названием субъекта бизнеса, которое
указывается вами при запуске приложения.
SOAPBodyElement findBusiness =
body.addBodyElement(
envelope.createName("find_business",
"", "urn:uddi-org:api"));
findBusiness.addAttribute(
envelope.createName("generic", "1.0");
findBusiness.addAttribute(
envelope.createName("maxRows", "100");
SOAPElement businessName =
findBusiness.addChildElement(
envelope.createName("name"));
businessName.addTextNode(args[1]);
В следующей строке кода создается Java Object, представляющий пункт назначения
сообщения. Он получает значение свойства с названием "URL" из файла системных
свойств.
Web-
Rendered by www.RenderX.com
Примеры приложений Стр. 363 из 626
Object endpoint =
System.getProperties().getProperty("URL");
В следующей строке сохраняются сделанные в сообщении изменения. Этот метод будет
вызываться автоматически при передаче сообщения, но ничего страшного не произойдет
и при его явном вызове.
msg.saveChanges();
Затем сообщение msg передается в пункт назначения, представленный в endpoint, которым
является UDDI-реестр. Метод call блокируется до получения объекта SOAPMessage назад,
после чего возвращает ответ.
SOAPBody replyBody =
reply.getSOAPPart().getEnvelope().getBody();
Затем вы можете вывести две пустых строки для отделения вашего результата от XML-
сообщения и третью строку, описывающую последующий текст.
System.out.println("");
System.out.println("");
System.out.print(
"Content extracted from the reply message: ");
Теперь вы можете начать процесс получения всех дочерних элементов из элемента,
получения дочерних элементов от каждого из них, и так далее до тех пор, пока не достигнете
Web-
Rendered by www.RenderX.com
Стр. 364 из 626 Java API for XML Messaging
Web-
Rendered by www.RenderX.com
Примеры приложений Стр. 365 из 626
Iterator iter2 =
bodyElement.getChildElements();
while (iter2.hasNext()) {
SOAPElement child2 =
(SOAPElement)iter2.next();
Iterator iter3 =
child2.getChildElements();
String content = child2.getValue();
System.out.println(content);
while (iter3.hasNext()) {
SOAPElement child3 =
(SOAPElement)iter3.next();
Iterator iter4 =
child3.getChildElements();
content = child3.getValue();
System.out.println(content);
while (iter4.hasNext()) {
SOAPElement child4 =
(SOAPElement)iter4.next();
content = child4.getValue();
System.out.println(content);
}
}
}
}
connection.close();
} catch (Exception ex) {
ex.printStackTrace();
}
}
}
Для компиляции MyUddiPing.java выполните следующую команду:
ant build
После компиляции вы готовы запустить MyUddiPing. Следующая команда вызовет
программу java с .class-файлом для MyUddiPing, который принимает два аргумента. Первый
аргумент - это файл uddi.properties, который предоставляется установкой свойства в
build.xml. Второй аргумент - это имя бизнеса, описание которого вы хотите получить. Вы
должны указывать этот аргумент в командной строке. Обратите внимание, что установка
любого свойства в командной строке переопределяет значение, установленное для этого
свойства в файле build.xml. Последний аргумент, предоставляемый ant, всегда является
заданием, которой в данном случае является run.
Web-
Rendered by www.RenderX.com
Стр. 366 из 626 Java API for XML Messaging
cd <JWSDP_HOME>/samples/jaxm/myuddiping
ant -Dbusiness-name="Oracle" run
После полного XML-сообщения отобразится следующая информация. Она генерируется
кодом, добавленным в MyUddiPing.java.
Oracle
oracle powers the internet
Oracle Corporation
Oracle Corporation provides the software and services for e-
business.
Выполнение ant со свойством business-name Microsoft вместо Oracle генерирует следующую
информацию:
Microsoft Corporation
Computer Software and Hardware Manufacturer
11.4.3. SOAPFaultTest.java
Код SOAPFaultTest.java, основанный на фрагментах кода из предыдущего раздела ("Ошибки
SOAP"), создает сообщение с объектом SOAPFault. Он, также, извлекает содержимое
объекта SOAPFault и распечатывает его. Код приложения SOAPFaultTest находится в
каталоге
Web-
Rendered by www.RenderX.com
Примеры приложений Стр. 367 из 626
<JWSDP_HOME>/docs/tutorial/examples/jaxm/fault/src
Ниже приведен файл SOAPFaultTest.java.
import javax.xml.soap.*;
import java.util.*;
fault.setFaultCode("Client");
fault.setFaultString(
"Message does not have necessary info");
fault.setFaultActor("http://gizmos.com/order");
msg.saveChanges();
// SOAPFault
Web-
Rendered by www.RenderX.com
Стр. 368 из 626 Java API for XML Messaging
//
if ( body.hasFault() ) {
fault = body.getFault();
String code = fault.getFaultCode();
String string = fault.getFaultString();
String actor = fault.getFaultActor();
detail = fault.getDetail();
if ( detail != null) {
Iterator it = detail.getDetailEntries();
while ( it.hasNext() ) {
entry = (DetailEntry)it.next();
String value = entry.getValue();
System.out.println(" Detail entry = " + value);
}
}
} catch (Exception ex) {
ex.printStackTrace();
}
}
}
<JWSDP_HOME>/docs/tutorial/examples/jaxm/fault.
Этот ant-файл выполняет за вас много действий, включая создание каталога build, где
будут размещаться файлы классов, создание переменной classpath, необходимой для
выполнения SOAPFaultTest, компиляцию SOAPFaultTest.java, помещение выходных .class-
файлов в каталог build и выполнение SOAPFaultTest.
Для запуска SOAPFaultTest выполните следующие действия:
1. Перейдите в каталог, в котором находится соответствующий файл build.xml.
Web-
Rendered by www.RenderX.com
Примеры приложений Стр. 369 из 626
cd <JWSDP_HOME>/docs/tutorial/examples/jaxm/fault
2. Из командной строки выполните следующую команду:
ant prepare
Эта команда создаст каталог build - каталог, в который будут помещаться файлы
классов.
3. Из командной строки выполните следующую команду:
ant build
Эта команда запустит программу javac с SOAPFaultTest.java, используя переменную
classpath, установленную в файле build.xml. Выходной .class-файл будет помещен в
каталог build, созданный в предыдущем задании.
4. Из командной строки выполните следующую команду:
ant run
Эта команда выполнит программу java SOAPFaultTest.
Обратите внимание, что для ускорения набора вы можете просто ввести ant run.
Необходимые задания будут выполнены в соответствующей последовательности, поскольку,
если задание указывает, что оно зависит от одного или более других заданий, эти задания
будут выполнены перед выполнением указанного задания. В данном случае задание run
зависит от задания build, которое, в свою очередь, зависит от задания prepare, то есть
задания prepare, build и run будут выполнены именно в этом порядке. Для еще большего
ускорения набора вы можете просто ввести ant. Заданием по умолчанию для файла
build.xml является run, то есть, выполнение ant имеет тот же эффект, что и выполнение
ant run.
Если вы хотите запустить SOAPFaultTest повторно, имеет смысл удалить каталог build и
.class-файлы, которые он содержит. Вы можете сделать это, выполнив следующую команду:
ant clean
После выполнения SOAPFaultTest вы увидите примерно следующее:
Web-
Rendered by www.RenderX.com
Стр. 370 из 626 Java API for XML Registries
env:faultstring><soap-env:faultactor>http://gizmos.com/order
</soap-env:faultactor><soap-env:Detail><PO:order xmlns:PO=
"http://gizmos.com/orders/">quantity element does not have a
value</PO:order><PO:confirmation xmlns:PO="http://gizmos.com/
confirm">Incomplete address: no zip code</PO:confirmation>
</soap-env:Detail></soap-env:Fault></soap-env:Body></soap-env:
Envelope>
11.4.4. Заключение
JAXM предоставляет Java API, который упрощает написание и передачу XML-сообщений.
Вы узнали, как писать код клиентского приложения для сообщений типа запрос-ответ и
однонаправленных сообщений. Вы также узнали, как получить содержимое из ответного
сообщения. Эти знания были применены при написании и выполнении примеров MyUddiPing
и SOAPFaultTest. Кроме того, дополнительный раздел "Приложение The Coffee Break"
предоставляет детальные примеры JAXM-кода как для клиента, так и для сервера.
Теперь вы хорошо представляете себе, как JAXM упрощает обмен XML-сообщениями.
Web-
Rendered by www.RenderX.com
Обзор JAXR Стр. 371 из 626
http://java.sun.com/xml/downloads/jaxr.html
В данной редакции Java WSDP JAXR реализует профиль возможностей нулевого уровня,
определенный в спецификации JAXR. Этот уровень разрешает доступ к реестрам UDDI и
ebXML на базовом уровне. В данной редакции JAXR поддерживает только реестры UDDI
версии 2.
В настоящее время существует несколько реестров UDDI версии 2. Сервер реестра Java
WSDP предоставляет реестр UDDI версии 2, который вы можете использовать для
Web-
Rendered by www.RenderX.com
Стр. 372 из 626 Java API for XML Registries
Web-
Rendered by www.RenderX.com
Реализация JAXR-клиента Стр. 373 из 626
Многие методы в JAXR API используют объект Collection в качестве аргумента или типа
возвращаемого значения. Использование объекта Collection разрешает проводить
одновременно операции с несколькими объектами реестра.
На рисунке 11-1 изображена архитектура JAXR. В Java WSDP, JAXR-клиент использует
интерфейсы нулевого уровня возможностей JAXR API для доступа к JAXR-поставщику.
JAXR-поставщик, в свою очередь, обращается к реестру. Java WSDP реализует поддержку
JAXR-поставщика для UDDI-реестров.
Web-
Rendered by www.RenderX.com
Стр. 374 из 626 Java API for XML Registries
import javax.xml.registry.*;
...
ConnectionFactory connFactory =
ConnectionFactory.newInstance();
Web-
Rendered by www.RenderX.com
Реализация JAXR-клиента Стр. 375 из 626
props.setProperty("com.sun.xml.registry.http.proxyHost",
"myhost.mydomain");
props.setProperty("com.sun.xml.registry.http.proxyPort",
"8080");
props.setProperty("com.sun.xml.registry.https.proxyHost",
"myhost.mydomain");
props.setProperty("com.sun.xml.registry.https.proxyPort",
"8080");
Затем клиент устанавливает свойства центра соединений и создает соединение:
connFactory.setProperties(props);
Connection connection = connFactory.createConnection();
Метод makeConnection в примере программы показывает шаги, выполняемые при создании
JAXR-соединения.
Web-
Rendered by www.RenderX.com
Стр. 376 из 626 Java API for XML Registries
Web-
Rendered by www.RenderX.com
Реализация JAXR-клиента Стр. 377 из 626
"https://uddi.ibm.com/testregistry/protect/publishapi");
ConnectionFactory factory = ConnectionFactory.newInstance();
factory.setProperties(props);
connection = factory.createConnection();
• Свойства postalAdressScheme, useCache и useSOAP могут быть установлены в теге
<sysproperty> в файле build.xml для программы ant. Например:
RegistryService rs = connection.getRegistryService();
BusinessQueryManager bqm = rs.getBusinessQueryManager();
BusinessLifeCycleManager blcm =
rs.getBusinessLifeCycleManager();
Обычно клиент получает оба объекта - и объект BusinesQueryManager, и объект BusinessLife-
CycleManager из объекта RegistryService. Если он использует реестр только для простых
запросов, ему необходимо получить только объект BusinessQueryManager.
Web-
Rendered by www.RenderX.com
Стр. 378 из 626 Java API for XML Registries
//
//
BulkResponse response =
bqm.findOrganizations(findQualifiers,
namePatterns, null, null, null, null);
Collection orgs = response.getCollection();
Клиент может использовать знак процента (%) для указания того, что строка запроса может
встретиться в любом месте названия организации. Например, в следующем фрагменте
программы выполняется поиск организаций (учитывается регистр символов), чьи названия
содержат qString:
Web-
Rendered by www.RenderX.com
Реализация JAXR-клиента Стр. 379 из 626
// ,
qString
BulkResponse response =
bqm.findOrganizations(findQualifiers, namePatterns, null,
null, null, null);
Collection orgs = response.getCollection();
ClassificationScheme cScheme =
bqm.findClassificationSchemeByName(null,
"ntis-gov:naics");
Classification classification =
blcm.createClassification(cScheme,
"Snack and Nonalcoholic Beverage Bars", "722213");
Collection classifications = new ArrayList();
classifications.add(classification);
// JAXR-
BulkResponse response = bqm.findOrganizations(null,
null, classifications, null, null, null);
Collection orgs = response.getCollection();
Вы можете использовать классификацию для поиска организаций, предлагающих службы,
основанные на технических спецификациях в форме WSDL-документов (Web Services
Description Language). В JAXR в качестве прокси для хранения информации о спецификации
используется концепт. Процедура поиска немного более сложная, чем в предыдущем
примере, поскольку клиент должен сначала найти концепт спецификации, а затем
организации, использующие этот концепт.
В следующем фрагменте программы выполняется поиск всех экземпляров WSDL-
спецификаций, используемых в данном реестре. Как вы можете заметить, программа
похожа на фрагмент кода запроса NAICS, за исключением того, что он заканчивается
вызовом findConcepts вместо findOrganizations.
Web-
Rendered by www.RenderX.com
Стр. 380 из 626 Java API for XML Registries
/*
* , ,
* ,
WSDL-
* UDDI.
*/
Classification wsdlSpecClassification =
blcm.createClassification(uddiOrgTypes,
"wsdlSpec", "wsdlSpec");
//
BulkResponse br = bqm.findConcepts(null, null,
classifications, null, null);
Для сужения поиска вы могли бы использовать другие аргументы метода findConcepts
(квалификаторы поиска, названия, внешние идентификаторы или внешние ссылки).
Следующий шаг - просмотреть концепты, найти WSDL-документы, которым они
соответствуют, и отобразить организации, использующие каждый документ:
//
Web-
Rendered by www.RenderX.com
Реализация JAXR-клиента Стр. 381 из 626
if (links.size() > 0) {
ExternalLink link =
(ExternalLink) links.iterator().next();
System.out.println("\tURL of WSDL document: '" +
link.getExternalURI() + "'");
}
// ,
//
...
}
Если вы нашли организации, предлагающие нужную вам службу, вы можете вызвать эту
службу, используя JAX-RPC API.
Web-
Rendered by www.RenderX.com
Стр. 382 из 626 Java API for XML Registries
//
PasswordAuthentication passwdAuth =
new PasswordAuthentication(username,
password.toCharArray());
Web-
Rendered by www.RenderX.com
Реализация JAXR-клиента Стр. 383 из 626
//
Organization org =
blcm.createOrganization("The Coffee Break");
InternationalString s =
blcm.createInternationalString("Purveyor of " +
"the finest coffees. Established 1895");
org.setDescription(s);
// ,
//
//
EmailAddress emailAddress =
blcm.createEmailAddress("jane.doe@TheCoffeeBreak.com");
Collection emailAddresses = new ArrayList();
emailAddresses.add(emailAddress);
primaryContact.setEmailAddresses(emailAddresses);
//
org.setPrimaryContact(primaryContact);
Web-
Rendered by www.RenderX.com
Стр. 384 из 626 Java API for XML Registries
// NAICS
ClassificationScheme cScheme =
bqm.findClassificationSchemeByName(null, "ntis-gov:naics");
Затем клиент создает классификацию, используя классификационную схему и концепт
(элемент таксономии) в классификационной схеме. Например, в следующем коде для
организации устанавливается классификация в NAICS-таксономии. Второй и третий
аргументы метода createClassification являются названием и значением концепта.
//
Classification classification =
blcm.createClassification(cScheme,
"Snack and Nonalcoholic Beverage Bars", "722213");
Collection classifications = new ArrayList();
classifications.add(classification);
org.addClassifications(classifications);
Службы также используют классификации, поэтому вы можете использовать похожий код
для добавления классификации в объект Service.
Web-
Rendered by www.RenderX.com
Реализация JAXR-клиента Стр. 385 из 626
// services service
Collection services = new ArrayList();
Service service = blcm.createService("My Service Name");
InternationalString is =
blcm.createInternationalString("My Service Description");
service.setDescription(is);
//
Collection serviceBindings = new ArrayList();
ServiceBinding binding = blcm.createServiceBinding();
is = blcm.createInternationalString("My Service Binding " +
"Description");
binding.setDescription(is);
// URL
binding.setValidateURI(false);
binding.setAccessURI("http://TheCoffeeBreak.com:8080/sb/");
serviceBindings.add(binding);
//
service.addServiceBindings(serviceBindings);
// service services,
services
//
services.add(service);
org.addServices(services);
//
//
Web-
Rendered by www.RenderX.com
Стр. 386 из 626 Java API for XML Registries
String id = key.getId();
System.out.println("Deleting organization with id " + id);
Collection keys = new ArrayList();
keys.add(key);
BulkResponse response = blcm.deleteOrganizations(keys);
Collection exceptions = response.getException();
if (exceptions == null) {
System.out.println("Organization deleted");
Collection retKeys = response.getCollection();
Iterator keyIter = retKeys.iterator();
javax.xml.registry.infomodel.Key orgKey = null;
if (keyIter.hasNext()) {
orgKey =
(javax.xml.registry.infomodel.Key) keyIter.next();
id = orgKey.getId();
Web-
Rendered by www.RenderX.com
Реализация JAXR-клиента Стр. 387 из 626
<PredefinedConcepts>
<JAXRClassificationScheme id="schId" name="schName">
<JAXRConcept id="schId/conCode" name="conName"
parent="parentId" code="conCode"></JAXRConcept>
...
</JAXRClassificationScheme>
</PredefinedConcepts>
Структура таксономии является структурой, основанной на включениях. Элемент Prede-
finedConcepts является корнем структуры и должен присутствовать. Элемент JAXRClasifi-
cationScheme является родительским элементом структуры, а элементы JAXRConcept
являются детьми и внуками. Элемент JAXRConcept может иметь детей, но это не
обязательно.
Web-
Rendered by www.RenderX.com
Стр. 388 из 626 Java API for XML Registries
ClassificationScheme cScheme =
blcm.createClassificationScheme("MyScheme",
"A Classification Scheme");
ClassificationScheme uddiOrgTypes =
bqm.findClassificationSchemeByName(null,
"uddi-org:types");
if (uddiOrgTypes != null) {
Classification classification =
blcm.createClassification(uddiOrgTypes,
"postalAddress", "categorization" );
postalScheme.addClassification(classification);
ExternalLink externalLink =
blcm.createExternalLink("http://www.mycom.com/myscheme.html",
"My Scheme");
postalScheme.addExternalLink(externalLink);
Collection schemes = new ArrayList();
schemes.add(cScheme);
BulkResponse br =
blcm.saveClassificationSchemes(schemes);
}
Объект BulkResponse, возвращенный методом saveClassificationSchemes, содержит
ключ для классификационной схемы, которую вы должны извлечь:
if (br.getStatus() == JAXRResponse.STATUS_SUCCESS) {
System.out.println("Saved ClassificationScheme");
Collection schemeKeys = br.getCollection();
Iterator keysIter = schemeKeys.iterator();
while (keysIter.hasNext()) {
javax.xml.registry.infomodel.Key key =
(javax.xml.registry.infomodel.Key)
keysIter.next();
Web-
Rendered by www.RenderX.com
Реализация JAXR-клиента Стр. 389 из 626
<JAXRClassificationScheme id="uuid:nnnnnnnn-nnnn-nnnn-nnnn-
nnnnnnnnnnnn" name="MyScheme">
ClassificationScheme id дожен быть UUID.
3. Введите каждый элемент JAXRConcept в ваш XML-файл таксономии, указывая
следующие четыре атрибута в следующем порядке:
A. id - это значение JAXRClassificationScheme id, за которым идет разделитель /, и код
элемента JAXRConcept
B. name - это имя элемента JAXRConcept
C. parent - это id прямого родителя (либо ClassificationScheme id, либо id родительского
JAXRConcept)
D. code - это значение кода элемента JAXRConcept
Первый элемент JAXRConcept в файле naics.xml выглядит следующим образом (все
в одной строке):
<JAXRConcept id="uuid:C0B9FE13-179F-413D-8A5B-5004DB8E5BB2/11"
java myProgram
-DuserTaxonomyFilenames=c:\myfile\xxx.xml|c:\myfile\xxx2.xml
Вы можете использовать тег <sysproperty> для установки этого свойства в файле
build.xml. Или вы можете установить свойство в вашей программе следующим образом:
Web-
Rendered by www.RenderX.com
Стр. 390 из 626 Java API for XML Registries
System.setProperty
("com.sun.xml.registry.userTaxonomyFilenames",
"c:\myfile\xxx.xml|c:\myfile\xxx2.xml");
<JAXRClassificationScheme id="uuid:6EAF4B50-4196-11D6-9E2B-
000629DC0A2B" name="IBMDefaultPostalAddressAttributes">
Прежде всего, вы указываете схему почтового адреса, используя значение id из элемента
JAXRClassificationScheme (UUID). Регистр не имеет значения:
props.setProperty("javax.xml.registry.postalAddressScheme",
"uuid:6eaf4b50-4196-11d6-9e2b-000629dc0a2b");
Затем, вы указываете отображение id каждого элемента JAXRConcept в схеме почтового
адреса JAXR по умолчанию в id его эквивалента в IBM-схеме:
props.setProperty("javax.xml.registry.semanticEquivalences",
"urn:uuid:PostalAddressAttributes/StreetNumber," +
"urn:uuid:6eaf4b50-4196-11d6-9e2b-
Web-
Rendered by www.RenderX.com
Реализация JAXR-клиента Стр. 391 из 626
000629dc0a2b/StreetAddressNumber|" +
"urn:uuid:PostalAddressAttributes/Street," +
"urn:uuid:6eaf4b50-4196-11d6-9e2b-
000629dc0a2b/StreetAddress|" +
"urn:uuid:PostalAddressAttributes/City," +
"urn:uuid:6eaf4b50-4196-11d6-9e2b-000629dc0a2b/City|" +
"urn:uuid:PostalAddressAttributes/State," +
"urn:uuid:6eaf4b50-4196-11d6-9e2b-000629dc0a2b/State|" +
"urn:uuid:PostalAddressAttributes/PostalCode," +
"urn:uuid:6eaf4b50-4196-11d6-9e2b-000629dc0a2b/ZipCode|" +
"urn:uuid:PostalAddressAttributes/Country," +
"urn:uuid:6eaf4b50-4196-11d6-9e2b-000629dc0a2b/Country");
После создания соединения с использованием этих свойств вы можете создать почтовый
адрес и присвоить его контактной информации организации перед опубликованием этой
организации:
Web-
Rendered by www.RenderX.com
Стр. 392 из 626 Java API for XML Registries
Web-
Rendered by www.RenderX.com
Реализация JAXR-клиента Стр. 393 из 626
## IBM:
#query.url=http://uddi.ibm.com/testregistry/inquiryapi
#publish.url=https://uddi.ibm.com/testregistry/protect/publish
api
## Microsoft:
#query.url=http://uddi.microsoft.com/inquire
#publish.url=https://uddi.microsoft.com/publish
## Registry Server:
query.url=http://localhost:8080/registry-
server/RegistryServerServlet
publish.url=http://localhost:8080/registry-
server/RegistryServerServlet
Оба реестра - и IBM, и Microsoft - содержат огромное количество данных, к которым
вы можете выполнять запросы. Кроме того, вам не нужно регистрироваться, если вы
собираетесь только лишь выполнять запросы. Мы не включили URL SAP-реестра;
можете добавить его самостоятельно. Если вы хотите опубликовать данные в любом
из публичных реестров, процесс регистрации для получения доступа к ним не является
трудным (см. раздел "Начальные сведения: получение доступа к реестру"). Однако
каждый из них позволяет вам одновременно иметь только одну зарегистрированную
организацию. Если вы опубликовали организацию в один из них, вы должны удалить
ее перед тем, как сможете опубликовать другую. Поскольку организации, публикуемые
примером JAXRPublish, являются вымышленными, вы должны удалить их сразу же в
любом случае. (Очень важно удалить эти организации сразу же, поскольку публичные
реестры тиражируют данные друг друга, и ваша вымышленная организация может
появиться не в том реестре, в который вы ее публиковали, и из него вы уже не сможете
ее удалить.) Сервер реестра дает вам больше свободы для экспериментов с JAXR.
Вы можете опубликовать столько организаций, сколько захотите. Однако этот реестр
поставляется с пустой базой данных, поэтому вы должны опубликовать организации
в нем самостоятельно перед тем, как сможете выполнять запросы к данным.
2. Отредактируйте следующие строки файла JAXRExamples.properties для указания имени
пользователя и пароля, полученного вами при регистрации в реестре. По умолчанию
указан пароль к серверу реестра.
Web-
Rendered by www.RenderX.com
Стр. 394 из 626 Java API for XML Registries
http.proxyHost=proxyhost.mydomain
http.proxyPort=8080
https.proxyHost=proxyhost.mydomain
https.proxyPort=8080
4. Свободно меняйте любые данные по организации в оставшейся части файла. Эти
данные используются примерами публикации и примерами, работающими с почтовыми
адресами.
ant build
для компиляции всех примеров. Программа ant создает подкаталог build и помещает в нем
файлы классов.
Вы увидите, что установка переменной classpath в файле build.xml включает содержимое
каталогов common/lib и common/endorsed. Все примеры JAXR-клиентов требуют такой
установки classpath.
Web-
Rendered by www.RenderX.com
Реализация JAXR-клиента Стр. 395 из 626
ant run-publish
Программа отобразит строковое значение ключа новой организации под названием "The
Coffee Break".
После выполнения программы JAXRPublish, но перед запуском JAXRDelete, вы можете
выполнить программу JAXRQuery для поиска организации, которую опубликовали. Вы
можете, также, использовать броузер реестра для ее поиска.
ant run-query-naics
ant run-query-wsdl
Этот пример возвращает много результатов из публичных реестров и может выполняться
несколько минут.
Web-
Rendered by www.RenderX.com
Стр. 396 из 626 Java API for XML Registries
ant run-save-scheme
Программа возвращает строку UUID, которая будет использоваться в следующем разделе.
Вы не должны запускать эту программу, если используете сервер реестра, поскольку она
не работает с этими объектами.
Публичные реестры позволяют вам владеть более чем одной классификационной схемой
одновременно (предел обычно устанавливается равным 10 для всех схем классификации
и концептов вместе).
<sysproperty key="com.sun.xml.registry.userTaxonomyFilenames"
value="postalconcepts.xml"/>
Укажите строку, введенную в файл postalconcepts.xml, как входную для задания run-
publish-postal:
Web-
Rendered by www.RenderX.com
Дополнительная информация Стр. 397 из 626
ant run-get-objects
ant clean
Для получения вспомогательной информации по синтаксису заданий используйте команду:
ant -projecthelp
Web-
Rendered by www.RenderX.com
Стр. 398 из 626 Технология Java Servlet
Web-
Rendered by www.RenderX.com
Примеры сервлетов Стр. 399 из 626
Web-
Rendered by www.RenderX.com
Стр. 400 из 626 Технология Java Servlet
Web-
Rendered by www.RenderX.com
Примеры сервлетов Стр. 401 из 626
C. Нажмите Next.
D. Выберите переключатель Servlet.
E. Нажмите Next.
F. В комбинированном окне Servlet Class выберите сервлет.
G. Нажмите Finish.
H. Таблица 12-2 Web-компоненты Duke's Bookstore
Имя Web-компонента Класс сервлета Псевдоним компонента
BookStoreServlet BookStoreServlet /enter
CatalogServlet CatalogServlet /catalog
BookDetailsServlet BookDetailsServlet /bookdetails
ShowCartServlet ShowCartServlet /showcart
CashierServlet CashierServlet /cashier
ReceiptServlet ReceiptServlet /receipt
Web-
Rendered by www.RenderX.com
Стр. 402 из 626 Технология Java Servlet
Web-
Rendered by www.RenderX.com
Жизненный цикл сервлета Стр. 403 из 626
Web-
Rendered by www.RenderX.com
Стр. 404 из 626 Технология Java Servlet
import database.BookDB;
import javax.servlet.*;
import util.Counter;
Web-
Rendered by www.RenderX.com
Жизненный цикл сервлета Стр. 405 из 626
<listener>
<listener-class>listeners.ContextListener</listener-class>
</listener>
Определите класс-слушатель для WAR-файла при помощи инспектора Event Listeners в
утилите deploytool (см. Слушатели событий).
<error-page>
<exception-type>
exception.BookNotFoundException
</exception-type>
<location>/errorpage.html</location>
</error-page>
<error-page>
<exception-type>
exception.BooksNotFoundException
</exception-type>
<location>/errorpage.html</location>
</error-page>
<error-page>
Web-
Rendered by www.RenderX.com
Стр. 406 из 626 Технология Java Servlet
<exception-type>exception.OrderException</exception-type>
<location>/errorpage.html</location>
</error-page>
Определите страницы ошибок для WAR-файла в инспекторе File Refs утилиты deploytool
(см. Отображения ошибок).
Web-
Rendered by www.RenderX.com
Использование совместного доступа к информации Стр. 407 из 626
Web-
Rendered by www.RenderX.com
Стр. 408 из 626 Технология Java Servlet
Web-
Rendered by www.RenderX.com
Инициализация сервлета Стр. 409 из 626
con.commit();
con.setAutoCommit(true);
releaseConnection();
} catch (Exception ex) {
try {
con.rollback();
releaseConnection();
throw new OrderException("Transaction failed: " +
ex.getMessage());
} catch (SQLException sqx) {
releaseConnection();
throw new OrderException("Rollback failed: " +
sqx.getMessage());
}
}
}
Web-
Rendered by www.RenderX.com
Стр. 410 из 626 Технология Java Servlet
Web-
Rendered by www.RenderX.com
Написание методов служб Стр. 411 из 626
Web-
Rendered by www.RenderX.com
Стр. 412 из 626 Технология Java Servlet
Web-
Rendered by www.RenderX.com
Написание методов служб Стр. 413 из 626
//
out.println("<html>" +
"<head><title>+
messages.getString("TitleBookDescription")
+</title></head>");
// dispatcher,
RequestDispatcher dispatcher =
getServletContext().
getRequestDispatcher("/banner");
if (dispatcher != null)
dispatcher.include(request, response);
//
Web-
Rendered by www.RenderX.com
Стр. 414 из 626 Технология Java Servlet
out.close();
}
}
Сервлет BookDetailsServlet генерирует страницу, которая выглядит следующим образом:
Web-
Rendered by www.RenderX.com
Фильтрация запросов и ответов Стр. 415 из 626
Web-
Rendered by www.RenderX.com
Стр. 416 из 626 Технология Java Servlet
Web-
Rendered by www.RenderX.com
Фильтрация запросов и ответов Стр. 417 из 626
Web-
Rendered by www.RenderX.com
Стр. 418 из 626 Технология Java Servlet
}
public CharResponseWrapper(HttpServletResponse response){
super(response);
output = new CharArrayWriter();
}
public PrintWriter getWriter(){
return new PrintWriter(output);
}
}
На Рисунке 12-3 показана вступительная страница Duke's Bookstore со счетчиком
посещений.
Web-
Rendered by www.RenderX.com
Фильтрация запросов и ответов Стр. 419 из 626
<filter>
<filter-name>OrderFilter</filter-name>
<filter-class>filters.OrderFilter</filter-class>
</filter>
<filter>
<filter-name>HitCounterFilter</filter-name>
<filter-class>filters.HitCounterFilter</filter-class>
</filter>
Элемент filter-mapping отображает фильтр заказа в URL-адрес/receipt. Отображение могло
также определить сервлет ReceiptServlet. Обратите внимание, что элементы filter, filter-
mapping, servlet и servlet-mapping должны появляться в дескрипторе размещения Web-
приложения в следующем порядке.
<filter-mapping>
<filter-name>OrderFilter</filter-name>
<url-pattern>/receipt</url-pattern>
</filter-mapping>
<filter-mapping>
<filter-name>HitCounterFilter</filter-name>
<url-pattern>/enter</url-pattern>
</filter-mapping>
Если вы желаете вести журнал запросов к Web-приложению, необходимо отобразить
фильтр счетчика посещений в URL-структуру /*. В Таблице 12-7 представлен список
отображений фильтров приложения Duke's Bookstore. Фильтры совпадают по URL-структуре,
а каждая цепочка фильтров содержит только один фильтр.
Таблица 12-7 Список отображения фильтров приложения Duke's Bookstore
URL Фильтр
/enter HitCounterFilter
/receipt OrderFilter
Фильтр можно отобразить на один или более Web-ресурсов. Можно также отобразить
более одного фильтра на один Web-ресурс. Данный процесс проиллюстрирован на Рисунке
12-4, где фильтр F1 отображается на сервлеты S1, S2 и S3, Фильтр F2 отображается на
сервлет S2, а фильтр F3 отображается на сервлеты S1 и S2.
Web-
Rendered by www.RenderX.com
Стр. 420 из 626 Технология Java Servlet
Web-
Rendered by www.RenderX.com
Вызов других Web-ресурсов Стр. 421 из 626
include(request, response);
Если ресурс является статическим, метод include позволяет использовать програмный
процесс включения ресурсов на стороне сервера. Если ресурс является Web-компонентом,
включаемому Web-компоненту отправляется запрос, затем Web-компонент выполненяется,
после чего результат запуска будет включен в ответ. Включенный Web-компонент имеет
доступ к объекту запроса, однако он ограничен в своих действиях относительно объекта
ответа:
• Он может производить запись в тело ответа и фиксировать его.
• Он не может устанавливать заголовки или вызывать любые методы (к примеру,
setCookie), влияющие на заголовки ответа.
Шапка приложения Duke's Bookstore генерируется при помощи сервлета BannerServlet.
Обратите внимание, что реализуются оба метода doGet и doPost, так как сервлет
BannerServlet может быть отправлен из любого метода вызываюшего сервлета.
Web-
Rendered by www.RenderX.com
Стр. 422 из 626 Технология Java Servlet
RequestDispatcher dispatcher =
getServletContext().getRequestDispatcher("/banner");
if (dispatcher != null)
dispatcher.include(request, response);
}
Web-
Rendered by www.RenderX.com
Организация доступа к web-контексту Стр. 423 из 626
...
}
Метод forward следует использовать для передачи другому ресурсу ответственности за
создание ответа пользователю. Если вы уже получили доступ к объектам ServletOutput-
Stream или PrintWriter внутри сервлета, использование данного метода будет невозможным.
Он будет возбуждать исключение IllegalStateException.
Web-
Rendered by www.RenderX.com
Стр. 424 из 626 Технология Java Servlet
}
}
//
HttpSession session = request.getSession();
ShoppingCart cart =
(ShoppingCart)session.
getAttribute("cart");
...
//
Web-
Rendered by www.RenderX.com
Сохранение состояния клиента Стр. 425 из 626
Web-
Rendered by www.RenderX.com
Стр. 426 из 626 Технология Java Servlet
session.invalidate();
...
http://localhost:8080/bookstore1/cashier;
jsessionid=c0o7fszeb1
Если cookie-файлы включены, URL простой:
http://localhost:8080/bookstore1/cashier
Web-
Rendered by www.RenderX.com
Завершение работы сервлета Стр. 427 из 626
Web-
Rendered by www.RenderX.com
Стр. 428 из 626 Технология Java Servlet
Web-
Rendered by www.RenderX.com
Дополнительная информация Стр. 429 из 626
Web-
Rendered by www.RenderX.com
Стр. 430 из 626 Технология JavaServer Pages
Web-
Rendered by www.RenderX.com
Что такое JSP-страница? Стр. 431 из 626
• Директивы (<%@page ... %>) импортируют классы пакета java.util и класс MyLocales, а
также устанавливают тип содержания, возвращаемый страницей.
• Элемент jsp:useBean создает объект, содержащий набор регионов, и инициализирует
переменную, указывающую на этот объект.
• Скриптлеты (<% ... %> ) извлекают значение параметра запроса locale, производят
итерацию в наборе названий регионов и условно вставляют HTML-текст в вывод.
• Выражения (<%= ... %>) вставляют значение названия региона в ответ.
• Элемент jsp:include посылает запрос другой странице (date.jsp) и включает ответ в ответ
вызывающей страницы.
Web-
Rendered by www.RenderX.com
Стр. 432 из 626 Технология JavaServer Pages
<jsp:include page="date.jsp"/>
</body>
</html>
Для того чтобы создать, разместить и осуществить выполнение данной JSP-страницы:
1. В окне терминала перейдите в директорию docs/tutorial/examples/web/date.
2. Запустите ant build. Исполнитель build вызовет все необходимые компиляции и скопирует
файлы в директорию docs/tutorial/examples/web/date/build.
3. Запустите ant install. Исполнитель install оповестит Tomcat о том, что стал доступен
новый контекст.
4. Откройте URL даты http://localhost:8080/date.
Вы увидите комбинированное окно, чьими записями являются названия регионов. Выберите
требуемый регион и нажмите Get Date. После этого появится дата, выраженная способом,
характерным для данного региона.
Данные для приложения "книжный магазин" все еще хранятся в базе данных. Однако, со
вспомогательным объектом database.BookDB базы данных были произведены два
изменения:
• Вспомогательный объект базы данных был переписан для соответствия шаблонам
проектирования JavaBean-компонентов, как описано в разделе Правила создания
JavaBean-компонентов. Это изменение сделано для того, чтобы JSP-страницы могли
иметь доступ к вспомогательным объектам, используя элементы JSP-языка, характерные
для JavaBean-компонентов.
• Вместо того чтобы напрямую получать доступ к базе данных книжного магазина,
вспомогательный объект проходит через объект доступа к данным database.BookDAO.
Далее представлена реализация вспомогательного объекта базы данных. У компонента
имеются две переменные экземпляров: текущая книга и ссылка на корпоративный компонент
базы данных.
Web-
Rendered by www.RenderX.com
Примеры JSP-страниц Стр. 433 из 626
Web-
Rendered by www.RenderX.com
Стр. 434 из 626 Технология JavaServer Pages
<JWSDP_HOME>/work/Standard
Engine/localhost/context_root/pageName$jsp.java
<JWSDP_HOME>/work/Standard Engine/localhost/date/index$jsp.java
Обе фазы, как трансляции, так и компиляции, могут вызывать ошибки, которые
прослеживаются только при первом запросе к странице. Если ошибка встречается во
время трансляции страницы (например, в случае, когда транслятор встречает плохо
Web-
Rendered by www.RenderX.com
Жизненный цикл JSP-страницы Стр. 435 из 626
14.3.2. Выполнение
Вы можете контролировать различные параметры выполнения JSP-страниц при помощи
директив page. Директивы, имеющие отношение к буферизации вывода и обработке ошибок
обсуждаются далее. Рассмотрение других директив встречается в данной главе в контексте
задач разработчика конкретных страниц.
Больший размер буфера позволяет записать больший объем содержимого. Таким образом,
JSP-странице обеспечивается больше времени для установки соответствующих кодов и
заголовков статуса или же для отправки другому web-ресурсу. Меньший размер буфера
уменьшает загрузку памяти сервера и позволяет клиенту быстрее получать данные.
Web-
Rendered by www.RenderX.com
Стр. 436 из 626 Технология JavaServer Pages
Данная директива делает доступным для страницы ошибок объект исключения (типа
javax.servlet.jsp.JspException) таким образом, чтобы вы могли извлекать, интерпретировать
и возможно даже отображать информацию о причине возникновения исключительной
ситуации на странице ошибок.
Примечание: Вы можете также определять страницы ошибок для WAR-файла, который
содержит JSP-страницу. Если страницы ошибок определены как для WAR, так и для JSP-
страницы, вначале появляется страница ошибок JSP-страницы.
Web-
Rendered by www.RenderX.com
Создание статического содержимого Стр. 437 из 626
Web-
Rendered by www.RenderX.com
Стр. 438 из 626 Технология JavaServer Pages
14.6.1.2. Объекты-приложения
По возможности, режим работы приложения следует инкапсулировать в объекты так, чтобы
создатели страниц могли сфокусироваться на аспектах представления. Объекты могут
создаваться разработчиками, которые являются профессионалами в программировании
Java и в получении доступа к базам данных и другим службам. Существует четыре способа
для создания и использования объектов в JSP-странице.
• Переменные экземпляра и класса, относящиеся к классу сервлета JSP-страницы,
создаются в объявлениях и доступны в скриптлетах и выражениях.
• Локальные переменные класса сервлета JSP-страницы создаются и используются в
скриптлетах и выражениях.
• Атрибуты объектов области действия (см. Использование объектов области действия)
создаются и используются в скриптлетах и выражениях.
• JavaBean-компоненты могут создаваться и быть доступными при помощи
модернизированных JSP-элементов. Данные элементы обсуждаются в главе JavaBean-
компоненты в JSP-страницах. Вы также можете создавать JavaBean-компонент в
объявлении или скриптлете и вызывать методы JavaBean-компонента в скриптлете или
выражении.
Объявления, скриптлеты и выражения описаны в разделе JSP-элементы сценариев.
Web-
Rendered by www.RenderX.com
Создание динамического содержимого Стр. 439 из 626
Web-
Rendered by www.RenderX.com
Стр. 440 из 626 Технология JavaServer Pages
14.6.2.1. Объявления
JSP-объявление используется для объявления переменных и методов на языке создания
сценариев страницы. Синтаксис для объявления следующий:
<%!
private BookDBAO bookDBAO;
14.6.2.2. Скриптлеты
JSP-скриптлет используется для хранения какого-либо фрагмента кода, действительного
для языка сценариев, используемого в данной странице. Синтаксис для скриптлета выглядит
следующим образом:
Web-
Rendered by www.RenderX.com
Создание динамического содержимого Стр. 441 из 626
<%
scripting language statements
%>
<%
Iterator i = cart.getItems().iterator();
while (i.hasNext()) {
ShoppingCartItem item =
(ShoppingCartItem)i.next();
BookDetails bd = (BookDetails)item.getItem();
%>
<tr>
<td align="right" bgcolor="#ffffff">
<%=item.getQuantity()%>
</td>
<td bgcolor="#ffffaa">
<strong><a href="
<%=request.getContextPath()%>/bookdetails?bookId=
<%=bd.getBookId()%>"><%=bd.getTitle()%></a></strong>
</td>
...
<%
// while
}
%>
Web-
Rendered by www.RenderX.com
Стр. 442 из 626 Технология JavaServer Pages
14.6.2.3. Выражения
JSP-выражение используется для вставки в поток данных, возвращаемый клиенту, значения
выражения языка сценариев, конвертированного в строку. Когда языком написания
сценариев является Java, выражение преобразовывается в оператор, конвертирующий
значение выражения в объект String и вставляющий его в неявный объект out.
Синтаксис такого выражения выглядит следующим образом:
<%
//
int num = cart.getNumberOfItems();
if (num> 0) {
%>
Позднее выражения используются для вставки значения num в выходной поток и задания
подходящей строки, которую требуется вставить после данного числа:
Web-
Rendered by www.RenderX.com
Включение содержимого в JSP-страницу Стр. 443 из 626
<font size="+2">
<%=messages.getString("CartContents")%><%=num%>
<%=(num==1 ? <%=messages.getString("CartItem")%> :
<%=messages.getString("CartItems"))%></font>
Например, все страницы приложения "книжный магазин" включают в себя файл banner.jsp,
в котором находится содержимое шапки. Это осуществляется при помощи следующей
директивы:
У данного подхода нет ограничений, так как директива include статически помещается в
каждый файл, повторно использующий ресурс, на который ссылается директива. Для того
чтобы узнать о более гибком подходе создания страниц данного типа, обратитесь к разделу
Библиотека тегов шаблона.
Web-
Rendered by www.RenderX.com
Стр. 444 из 626 Технология JavaServer Pages
<jsp:include page="date.jsp"/>
Обратите внимание, что если клиенту уже возвратили какие-либо данные, у элемента
jsp:forward возникнет исключительная ситуация IllegalStateException.
<jsp:include page="...">
<jsp:param name="param1" value="value1"/>
Web-
Rendered by www.RenderX.com
Включение апплета Стр. 445 из 626
</jsp:include>
<jsp:plugin
type="bean|applet"
code="objectCode"
codebase="objectCodebase"
{ align="alignment" }
{ archive="archiveList" }
{ height="height" }
{ hspace="hspace" }
{ jreversion="jreversion" }
{ name="componentName" }
{ vspace="vspace" }
{ width="width" }
{ nspluginurl="url" }
{ iepluginurl="url" } >
{ <jsp:params>
{ <jsp:param name="paramName" value= paramValue" /> }+
</jsp:params> }
{ <jsp:fallback> arbitrary_text </jsp:fallback> }
</jsp:plugin>
Тег jsp:plugin заменяется либо тегом <object>, либо тегом <embed>. Это зависит от клиента,
осуществляющего запрос. Атрибуты тега jsp:plugin обеспечивают данные конфигурации
для представления элемента, как того требует версия plug-in. Атрибуты nspluginurl и
iepluginurl задают URL-адрес, с которого этот plug-in можно загрузить.
Элементы jsp:param задают параметры апплета или JavaBean-компонента. Если plug-in
нельзя запустить (или теги <object> и <embed> не поддерживаются клиентом, или по какой-
либо другой причине), элемент jsp:fallback указывает на то, чтобы содержимое
просматривалось в броузере клиента.
Web-
Rendered by www.RenderX.com
Стр. 446 из 626 Технология JavaServer Pages
<jsp:plugin
type="applet"
code="DigitalClock.class"
codebase="/bookstore2"
jreversion="1.3"
align="center" height="25" width="300"
nspluginurl="http://java.sun.com/products/plugin/1.3.0_01
/plugin-install.html"
iepluginurl="http://java.sun.com/products/plugin/1.3.0_01
/jinstall-130_01-win32.cab#Version=1,3,0,1">
Web-
Rendered by www.RenderX.com
Расширение JSP-языка Стр. 447 из 626
<jsp:params>
<jsp:param name="language"
value="<%=request.getLocale().getLanguage()%>" />
<jsp:param name="country"
value="<%=request.getLocale().getCountry()%>" />
<jsp:param name="bgcolor" value="FFFFFF" />
<jsp:param name="fgcolor" value="CC0066" />
</jsp:params>
<jsp:fallback>
Unable to start plugin.
</jsp:fallback>
</jsp:plugin>
<%
Iterator i = cart.getItems().iterator();
while (i.hasNext()) {
ShoppingCartItem item =
(ShoppingCartItem)i.next();
...
%>
<tr>
<td align="right" bgcolor="#ffffff">
<%=item.getQuantity()%>
</td>
...
<%
}
Web-
Rendered by www.RenderX.com
Стр. 448 из 626 JavaBean-компоненты в JSP-страницах
%>
Заказной тег iterate устраняет логику кода и управляет переменной создания сценария
item, ссылающейся на элементы в корзине покупателя:
<logic:iterate id="item"
collection="<%=cart.getItems()%>">
<tr>
<td align="right" bgcolor="#ffffff">
<%=item.getQuantity()%>
</td>
...
</logic:iterate>
Web-
Rendered by www.RenderX.com
Правила создания JavaBean-компонентов Стр. 449 из 626
Web-
Rendered by www.RenderX.com
Стр. 450 из 626 JavaBean-компоненты в JSP-страницах
<%
ShoppingCart cart = (ShoppingCart)session.
getAttribute("cart");
// ,
if (cart == null) {
cart = new ShoppingCart();
session.setAttribute("cart", cart);
}
%>
Web-
Rendered by www.RenderX.com
Создание и использование JavaBean-компонентов Стр. 451 из 626
<jsp:useBean id="beanName"
class="fully_qualified_classname" scope="scope"/>
или
<jsp:useBean id="beanName"
class="fully_qualified_classname" scope="scope">
<jsp:setProperty .../>
</jsp:useBean>
Web-
Rendered by www.RenderX.com
Стр. 452 из 626 JavaBean-компоненты в JSP-страницах
Набор свойств из строковой константы или параметра запроса должен иметь тип из списка,
представленного в Таблице14-2. Так как и константа, и параметр запроса являются
строками, Web-контейнер автоматически конвертирует значение в тип свойства. Сам
процесс преобразования отражен в таблице. Значения String могут использоваться для
присваивания значений свойству класса PropertyEditor. В этом случае используется метод
setAsText(String). Если метод бросает исключение IllegalArgumentException, возникает
ошибка преобразования. Значением, присваиваемым индексированному свойству, должен
быть массив, а только что описанные правила применяются к его элементам.
Таблица 14-2 Правильные значения свойств
Тип свойства Преобразование строкового значения
Свойство компонента Использует setAsText(string-literal)
boolean или Boolean Как показано в java.lang.Boolean.valueOf(String)
byte или Byte Как показано в java.lang.Byte.valueOf(String)
char или Character Как показано в java.lang.String.charAt(0)
double или Double Как показано в java.lang.Double.valueOf(String)
Web-
Rendered by www.RenderX.com
Установление свойств JavaBean-компонентов Стр. 453 из 626
Для установки значения свойства сложного типа языка программирования Java вам следует
использовать выражение рабочего цикла. Вспомните из раздела Выражения, что JSP-
выражение используется для внедрения в поток, возвращаемый клиенту, значения из
выражения языка создания сценариев, конвертированного в строку. Используя в элементе
setProperty, выражение просто возвращает свое значение без какого-либо автоматического
преобразования. Как следствие, тип, возвращаемый из выражения, должен соответствовать
типу свойства или сводиться к нему.
Приложение Duke's Bookstore демонстрирует, как необходимо использовать элемент
setProperty и скриптлет с целью установки текущей книги для вспомогательного компонента
базы данных. Например, bookstore3/web/bookdetails.jsp использует форму:
Web-
Rendered by www.RenderX.com
Стр. 454 из 626 JavaBean-компоненты в JSP-страницах
<%
//
int num = cart.getNumberOfItems();
if (num > 0) {
Web-
Rendered by www.RenderX.com
Извлечение свойств JavaBean-компонентов Стр. 455 из 626
%>
На Рисунке 14-1 показано, где хранятся различные типы объектов и как можно получить
доступ к этим объектам из JSP-страницы. Объекты, созданные при помощи тега jsp:useBean,
хранятся как атрибуты области действия объектов и доступны в скриптлетах и выражениях
при помощи тегов jsp:[get|set]Property. Объекты, созданные в объявлениях и скриптлетах
хранятся как переменные класса сервлета JSP-страницы и могут быть доступны в
скриптлетах и выражениях.
Web-
Rendered by www.RenderX.com
Стр. 456 из 626 Заказные теги в JSP-страницах
Web-
Rendered by www.RenderX.com
Примеры JSP-страниц Стр. 457 из 626
объектом под названием обработчик тега. Позднее, во время исполнения сервлета JSP-
страницы Web-контейнер вызывает данные операции.
У заказных тегов имеется большой набор характеристик. Они могут
• Настраиваться через атрибуты, передаваемые от вызывающей страницы.
• Организовывать доступ ко всем объектам, доступным для JSP-страниц.
• Изменять ответ, созданный вызывающей страницей.
• Взаимодействовать друг с другом. Вы можете создать и инициализировать JavaBean-
компонент, а также переменную, которая ссылается на этот компонент в одном теге, а
затем использовать этот компонент в другом теге.
• Быть вложенными друг в друга, позволяя осуществлять сложные взаимодействия в
пределах одной JSP-страницы.
Web-
Rendered by www.RenderX.com
Стр. 458 из 626 Заказные теги в JSP-страницах
Web-
Rendered by www.RenderX.com
Использование тегов Стр. 459 из 626
Данная директива taglib использует короткое логическое имя для косвенной ссылки на
TLD-файл:
Web-
Rendered by www.RenderX.com
Стр. 460 из 626 Заказные теги в JSP-страницах
<taglib>
<taglib-uri>/tutorial-template</taglib-uri>
<taglib-location>
/WEB-INF/tutorial-template.tld
</taglib-location>
</taglib>
<tt:tag>
body
</tt:tag>
<tt:tag />
Web-
Rendered by www.RenderX.com
Использование тегов Стр. 461 из 626
<tt:simple />
<logic:present parameter="Clear">
<logic:iterate collection="<%=bookDB.getBooks()%>"
id="book" type="database.BookDetails">
<logic:present parameter="Clear">
<% cart.clear(); %>
<font color="#ff0000" size="+2"><strong>
You just cleared your shopping cart!
Web-
Rendered by www.RenderX.com
Стр. 462 из 626 Заказные теги в JSP-страницах
</strong><br> <br></font>
</logic:present>
Web-
Rendered by www.RenderX.com
Определение тегов Стр. 463 из 626
<tt:outerTag>
<tt:innerTag />
</tt:outerTag>
Web-
Rendered by www.RenderX.com
Стр. 464 из 626 Заказные теги в JSP-страницах
по данному вопросу обратитесь к разделу Теги с телами. Для того, чтобы обеспечить
реализацию обработчика тега, вы должны реализовать методы, представленные в Таблице
15-1, которые вызываются на различных стадиях процесса обработки тега.
Таблица 15-1 Методы обработчиков тегов
Тип обработчика тега Методы
Простой doStartTag, doEndTag, release
Атрибуты doStartTag, doEndTag, set/getAttribute1...N, release
Тело, оценка без взаимодействия doStartTag, doEndTag, release
Тело, повторяющаяся оценка doStartTag, doAfterBody, doEndTag, release
Тело, взаимодействие doStartTag, doEndTag, release, doInitBody, doAfterBody, release
Tomcat поддерживает версии DTD 1.1 и 1.2. Тем не менее, в примерах данной главы
использована версия 1.2, так как при разработке любых библиотек тегов вы должны
использовать самую последнюю версию DTD-файла. TLD библиотеки tutorial-
templatetutorial-template.tld соответствует версии 1.2. TLD библиотеки Struts соответствует
Web-
Rendered by www.RenderX.com
Определение тегов Стр. 465 из 626
Web-
Rendered by www.RenderX.com
Стр. 466 из 626 Заказные теги в JSP-страницах
Элемент Описание
tei-class Подкласс (используется при необходимости)
javax.servlet.jsp.tagext.TagExtraInfo. См. Обеспечение
информации о переменной скрипта.
body-content Тип содержания тела. См. Элемент body-content и Элемент
body-content.
display-name Имя (используется при необходимости), предназначенное
для отображения утилитами
small-icon Маленькая иконка (используется при необходимости), которая
может быть использована в утилитах
large-icon Большая иконка (используется при необходимости), которая
может быть использована в утилитах
description Информация о теге (используется при необходимости)
variable Информация о переменной создания сценария (используется
при необходимости). См. Обеспечение информации о
переменной скрипта.
attribute Информация об атрибуте тега. См. Элемент атрибут.
<tt:simple />
Web-
Rendered by www.RenderX.com
Определение тегов Стр. 467 из 626
return SKIP_BODY;
}
public int doEndTag() {
return EVAL_PAGE;
}
}
<body-content>empty</body-content>
<logic:present parameter="Clear">
Обратите внимание, что если атрибут называется id, а обработчик тега наследуется от
класса TagSupport, определять свойство и методы set и get не требуется, так как они уже
определены в классе TagSupport.
Атрибут тега, значением которого является String, может присваивать имя атрибуту одного
из неявных объектов, доступных обработчикам тега. Доступ к атрибуту неявного объекта
можно получить, передав значение атрибута тега методу [set|get]Attribute неявного объекта.
Web-
Rendered by www.RenderX.com
Стр. 468 из 626 Заказные теги в JSP-страницах
<attribute>
<name>attr1</name>
<required>true|false|yes|no</required>
<rtexprvalue>true|false|yes|no</rtexprvalue>
<type>fully_qualified_type</type>
</attribute>
Если тег attribute не является необходимым, обработчик тега должен обеспечить значение
по-умолчанию.
Элемент tag для тега logic:present объявляет, что использование атрибута parameter не
является необходимым (так как тег может также проверять наличие других сущностей,
таких как свойства компонента) и, что его значение может быть установлено при помощи
выражения рабочего цикла.
<tag>
<name>present</name>
<tag-class>org.apache.struts.taglib.
logic.PresentTag</tag-class>
<body-content>JSP</body-content>
...
<attribute>
<name>parameter</name>
<required>false</required>
<rtexprvalue>true</rtexprvalue>
</attribute>
...
</tag>
Web-
Rendered by www.RenderX.com
Определение тегов Стр. 469 из 626
<attribute>
<name>attr1</name>
<required>true</required>
<rtexprvalue>true</rtexprvalue>
</attribute>
В данном объявлении указано, что значение attr1 может быть задано во время рабочего
цикла.
Следующий метод isValid проверяет, является ли значением attr1 правильное значение
типа Boolean. Обратите внимание на то, что значение attr1 может быть вычислено во время
рабочего цикла, поэтому метод isValid должен проверить, выбрал ли пользователь тега
обеспечение значения рабочего цикла.
Web-
Rendered by www.RenderX.com
Стр. 470 из 626 Заказные теги в JSP-страницах
}
}
Web-
Rendered by www.RenderX.com
Определение тегов Стр. 471 из 626
<body-content>JSP|tagdependent</body-content>
Содержимое тела, в котором имеются заказные теги, теги ядра, элементы создания
сценариев и HTML-текст, относится к категории JSP. Это значение объявлено для тега
logic:present библиотеки Struts. Все остальные типы содержимого тела (например, SQL-
выражения, передаваемые тегу запроса) будут обозначаться как tagdependent.
Web-
Rendered by www.RenderX.com
Стр. 472 из 626 Заказные теги в JSP-страницах
Web-
Rendered by www.RenderX.com
Определение тегов Стр. 473 из 626
property="title"/></strong>
<br> <br>
</font>
Web-
Rendered by www.RenderX.com
Стр. 474 из 626 Заказные теги в JSP-страницах
<tag>
<variable>
<name-from-attribute>id</name-from-attribute>
<variable-class>database.BookDetails</variable-class>
<declare>true</declare>
<scope>AT_BEGIN</scope>
</variable>
</tag>
Web-
Rendered by www.RenderX.com
Определение тегов Стр. 475 из 626
type,
true,
VariableInfo.AT_BEGIN)
};
}
}
<tei-class>
org.apache.struts.taglib.bean.DefineTagTei
</tei-class>
Web-
Rendered by www.RenderX.com
Стр. 476 из 626 Заказные теги в JSP-страницах
connection =(Connection)pageContext.
getAttribute(cid);
} else {
ConnectionTag ancestorTag =
(ConnectionTag)findAncestorWithClass(this,
ConnectionTag.class);
if (ancestorTag == null) {
throw new JspTagException("A query without
a connection attribute must be nested
within a connection tag.");
}
connection = ancestorTag.getConnection();
}
}
}
Тег запроса, реализованный данным обработчиком тега, может быть использован одним
из нижеприведенных способов:
<tt:connection ...>
<x:query id="balances">
SELECT account, balance FROM acct_table
Web-
Rendered by www.RenderX.com
Примеры Стр. 477 из 626
TLD для обработчика тега при помощи следующего объявления должен указывать на то,
что атрибут connection является необязательным:
<tag>
...
<attribute>
<name>connection</name>
<required>false</required>
</attribute>
</tag>
16.5. Примеры
Заказные теги, описанные в данном разделе, демонстрируют решения двух часто
встречающихся проблем в разработке JSP-приложений. Ими являются минимизация
объема Java-программирования на JSP-страницах и гарантия единого восприятия всех
приложений. При этом данные теги иллюстрируют множество стилей тегов, которые
обсуждались в первой части главы.
16.5.1.1. JSP-страница
Страницы catalog.jsp и showcart.jsp приложения Duke's Bookstore используют тег logic:iterate
для выполнения процесса итерации в коллекции объектов. Выдержка из страницы catalog.jsp
представлена ниже. JSP-страница инициализирует тег iterate с коллекцией (названной
атрибутом property) компонента bookDB. Тег iterate устанавливает переменную создания
сценарияbook при каждой итерации всей коллекции. Свойство bookId переменной book
используется как другая переменная создания сценария. Свойства обеих переменных
используются для динамического генерирования таблицы, содержащей ссылки на другие
страницы и информацию книжного каталога.
Web-
Rendered by www.RenderX.com
Стр. 478 из 626 Заказные теги в JSP-страницах
<tr>
<td bgcolor="#ffffaa">
<a href="<%=request.getContextPath()%>
/bookdetails?bookId=<%=bookId%>">
<strong><jsp:getProperty name="book"
property="title"/> </strong></a></td>
<tr>
<td bgcolor="#ffffff">
<%=messages.getString("By")%> <em>
<jsp:getProperty name="book"
property="firstName"/>
<jsp:getProperty name="book"
property="surname"/></em></td></tr>
</logic:iterate>
Web-
Rendered by www.RenderX.com
Примеры Стр. 479 из 626
Web-
Rendered by www.RenderX.com
Стр. 480 из 626 Заказные теги в JSP-страницах
if (collection == null) {
... throw an exception
}
} catch
... catch exceptions thrown
by PropertyUtils.getProperty
}
}
//
Web-
Rendered by www.RenderX.com
Примеры Стр. 481 из 626
}
}
}
Web-
Rendered by www.RenderX.com
Стр. 482 из 626 Заказные теги в JSP-страницах
16.5.2.1. JSP-страница
Далее представлен шаблон template.jsp для примера Duke's Bookstore. Данная страница
включает в себя JSP-страницу, создающую определение экрана, а затем использует тег
insert для вставки параметров из определения в окно приложения.
<tt:definition name="bookstore"
screen="<%= (String)request.
getAttribute(\"selectedScreen\") %>">
<tt:screen id="/enter">
<tt:parameter name="title"
value="Duke's Bookstore" direct="true"/>
<tt:parameter name="banner"
value="/banner.jsp" direct="false"/>
<tt:parameter name="body"
value="/bookstore.jsp" direct="false"/>
</tt:screen>
<tt:screen id="/catalog">
<tt:parameter name="title"
value="<%=messages.getString("TitleBookCatalog")%>"
direct="true"/>
Web-
Rendered by www.RenderX.com
Примеры Стр. 483 из 626
...
</tt:definition>
Web-
Rendered by www.RenderX.com
Стр. 484 из 626 Заказные теги в JSP-страницах
Web-
Rendered by www.RenderX.com
Примеры Стр. 485 из 626
...
if (params == null)
...
Iterator ir = null;
if (params != null)
ir = params.iterator();
while ((ir != null) && ir.hasNext())
definition.setParam((Parameter) ir.next());
//
pageContext.setAttribute(
definitionName, definition);
} catch (Exception ex) {
ex.printStackTrace();
}
return EVAL_PAGE;
}
InsertTag использует объект Definition для вставки параметров определения экрана в ответ.
В методе doStartTag он извлекает объект определения из контекста страницы.
Web-
Rendered by www.RenderX.com
Стр. 486 из 626 Заказные теги в JSP-страницах
directInclude = parameter.isDirect();
return SKIP_BODY;
}
Web-
Rendered by www.RenderX.com
Примеры Стр. 487 из 626
t.doStartTag();
t.doEndTag();
t.release();
t.doStartTag();
out = pageContext.pushBody();
t.setBodyContent(out);
// ,
t.doInitBody();
t.doAfterBody();
// doAfterBody EVAL_BODY_BUFFERED
//
...
t.doAfterBody();
t.doEndTag();
t.pageContext.popBody();
t.release();
Web-
Rendered by www.RenderX.com
Стр. 488 из 626 Стандартная библиотека тегов JavaServer-страниц
тег для заданной операции и использовать его в различных JSP-контейнерах. Кроме этого,
когда теги являются стандартными, контейнеры могут оптимизировать их реализацию.
У JSTL есть поддержка общих структурных задач, таких как итерация и задачи с условиями,
есть также теги управления XML-документами, теги интернационализации и теги для
организации доступа к базам данных, использующих язык SQL. Кроме этого, вводится
концепция языка выражений, упрощающая разработку страниц. JSTL, к тому же,
обеспечивает основу для интеграции существующих библиотек тегов с библиотекой JSTL.
В данной главе при рассмотрении библиотеки JSTL используются выдержки из JSP-версии
приложения Duke's Bookstore. Допускается, что вы уже знакомы с материалом раздела
Использование тегов главы 15.
Web-
Rendered by www.RenderX.com
Примеры JSP-страниц Стр. 489 из 626
Web-
Rendered by www.RenderX.com
Стр. 490 из 626 Стандартная библиотека тегов JavaServer-страниц
Web-
Rendered by www.RenderX.com
Использование JSTL Стр. 491 из 626
К примеру, для того чтобы использовать центральные теги JSTL и JSP-странице, объявите
библиотеку, используя директиву taglib, которая ссылается на TLD:
Библиотеки тегов JSTL выпускаются в двух версиях (см. Двойные библиотеки). TLD для
библиотеки JSTL-EL называются prefix.tld. TLD для библиотеки JSTL-RT называются prefix-
rt.tld. В виду того, что примеры, обсуждаемые в данной главе, используют логические TLD-
имена, мы отображаем логические имена в реальные TLD-локации с элементами taglib в
дескрипторе размещения Web-приложения. Далее представлен код, отображающий
центральное логическое TLD-имя библиотеки /jstl-c в свое местоположение /WEB-INF/c.tld:
Web-
Rendered by www.RenderX.com
Стр. 492 из 626 Стандартная библиотека тегов JavaServer-страниц
<taglib>
<taglib-uri>/jstl-c</taglib-uri>
<taglib-location>/WEB-INF/c.tld</taglib-location>
</taglib>
Web-
Rendered by www.RenderX.com
Поддержка языка выражений Стр. 493 из 626
<x:atag att="${aName}">
<x:aTag att="${aName.foo.bar}">
Web-
Rendered by www.RenderX.com
Стр. 494 из 626 Стандартная библиотека тегов JavaServer-страниц
Для значений литералов, которые содержат символ ${, следует применить переход:
17.3.2.1. Атрибуты
Доступ к атрибутам осуществляется по имени с дополнительной областью действия. К
свойствам атрибутов, которые могут быть вложены в любом порядке, доступ
осуществляется при помощи оператора точка (.).
EL объединяет обработку операторов . и []. Таким образом expr-a.expr-b эквивалентен
expr-a[expr-b]. Чтобы вычислить expr-a[expr-b], переведите значение expr-a в value-a, а
значение expr-b в value-b.
• Если value-a является Map, возвратите value-a.get(value-b).
• Если value-a является List массива, переведите value-b на int и возвратите value-
a.get(value-b) или Array.get(value-a, value-b), по обстоятельствам.
• Если же value-a является JavaBean-объектом, переведите value-b в String. Если value-
b - это читаемое свойство value-a, возвратится вызов.
EL оценивает идентификатор путем поиска его значения как атрибута, в соответствии с
поведением PageContext.findAttribute(String). Например, ${product} будет искать атрибут с
названием product в области действия страницы, запроса, сессии и приложения, после
чего возвратит его значение. Если атрибут не найден, возвратится null. Обратите внимание,
что идентификатор, который соответствует одному из неявных объектов, описанных в
следующем разделе, возвратит сам неявный объект вместо значения атрибута.
Web-
Rendered by www.RenderX.com
Поддержка языка выражений Стр. 495 из 626
17.3.2.3. Литералы
• Boolean: true и false
• Long: как в Java
• Floating point: как в Java
• String: с одиночными и двойными кавычками. " получено из \", ' получено из \', и \ получено
из \\.
• Null: null
Web-
Rendered by www.RenderX.com
Стр. 496 из 626 Стандартная библиотека тегов JavaServer-страниц
17.3.2.4. Операторы
EL обеспечивает следующие операторы:
• Арифметические: +, -, *, / и div, % и mod, -
• Логические: and, &&, or, ||, not, !
• Операторы сравнений: ==, eq, !=, ne, <, lt, >, gt, <=, ge, >=, le. Сравнивать можно и с
другими значениями или с литералами boolean, string, integer или floating point.
• Empty: Оператор empty является префиксной операцией, с помощью которой можно
определить, является ли значением null или empty.
Чтобы узнать больше о других возможностях данных операторов обратитесь к документу
Спецификация JSTL 1.0.
Имя var было выбрано для акцентирования внимания на том факте, что открытая
переменная области действия не является переменной создания сценария (что является
нормальным для атрибутов с именем id).
В ситуациях, когда теги представляют более одного блока информации, имя var
используется для первичного экспортируемого блока информации, причем соответствующее
имя выбирается и для любого другого вторичного представляемого блока информации. К
примеру, информация о статуте итерации экспортируется тегом forEach посредством
атрибута status.
Web-
Rendered by www.RenderX.com
Теги ядра Стр. 497 из 626
<c:out value="${sessionScope.cart.numberOfItems}"/>
Тег set устанавливает значение атрибута в любой области действия JSP (странице, запросе,
сессии, приложении). Если атрибут не существует, он создается.
Атрибут области действия JSP-страницы может быть установлен двумя способами: из
значения атрибута
<c:set var="foo">
...
</c:set>
Web-
Rendered by www.RenderX.com
Стр. 498 из 626 Стандартная библиотека тегов JavaServer-страниц
<c_rt:set var="bookId"
value="<%= request.getParameter("Remove") %>" />
Чтобы удалить атрибут области действия, используйте тег remove. Когда вызывается JSP-
страница receipt.jsp магазина, сессия покупки завершается, следовательно, сессионный
атрибут cart удаляется следующим образом:
Тег catch обеспечивает дополнение к механизму страницы ошибок JSP. Оно позволяет
авторам страницы оперативно разрешать ситуации сбоя, которые находятся у них под
контролем. Действия первостепенной важности для страницы не должны быть
инкапсулированы в catch, таким образом, их исключения будут распространяться на
страницу ошибок. Действия второстепенной важности для страницы должны быть
"завернуты" в catch, поэтому они никогда не вызовут механизма страницы ошибок.
Web-
Rendered by www.RenderX.com
Теги ядра Стр. 499 из 626
<%
Iterator i = cart.getItems().iterator();
while (i.hasNext()) {
ShoppingCartItem item =
(ShoppingCartItem)i.next();
...
%>
<tr>
<td align="right" bgcolor="#ffffff">
<%=item.getQuantity()%>
</td>
...
<%
}
%>
Web-
Rendered by www.RenderX.com
Стр. 500 из 626 Стандартная библиотека тегов JavaServer-страниц
dataSource="${applicationScope.bookDS}">
select * from PUBLIC.books where id = ?
<sql:param value="${bid}" />
</sql:query>
<c:forEach var="bookRow" begin="0" items="${books.rows}">
<jsp:useBean id="bookRow" type="java.util.Map" />
<jsp:useBean id="addedBook"
class="database.BookDetails" scope="page" />
...
<% cart.add(bid, addedBook); %>
...
</c:if>
Тег choose добавляет условия в выполнение блока путем вставки субтегов when. Он
отображает тело первого тега when, чьим тестовым условием является true. Если ни одним
из тестовых условий вложенных тегов when не является true, оценивается тело тега
otherwise, если таковой существует.
Примером может служить программный код, показывающий как отображать текст,
основываясь на категории покупателя.
<c:choose>
<c:when test="${customer.category == 'trial'}" >
...
</c:when>
<c:when test="${customer.category == 'member'}" >
...
</c:when>
<c:when test="${customer.category == 'preferred'}" >
...
</c:when>
<c:otherwise>
...
</c:otherwise>
</c:choose>
Теги choose, when и otherwise могут применяться для создания инструкции if-then-else
следующим образом:
<c:choose>
Web-
Rendered by www.RenderX.com
Теги ядра Стр. 501 из 626
Web-
Rendered by www.RenderX.com
Стр. 502 из 626 Стандартная библиотека тегов JavaServer-страниц
17.4.3. URL-теги
Элемент jsp:include обеспечивает включение статических и динамических ресурсов в тот
же контекст, что и текущая страница. Тем не менее, jsp:include не может получить доступ
к ресурсам, которые находятся вне Web-приложения. Это вызовет бесполезное
использование буфера, если включенный ресурс используется другим элементом.
В следующем примере элемент transform использует содержимое включенного ресурса,
как данные на входе его преобразования. Элемент jsp:include считывает содержимое
ответа, записывает его в содержимое тела закрывающего элемента преобразования,
который затем перечитывает то же содержимое. Было бы эффективнее, если бы элемент
transform мог получить доступ к входящему ресурсу напрямую и избежать использования
буфера для содержимого тела тега преобразования.
<acme:transform>
<jsp:include page="/exec/employeesList"/>
<acme:transform/>
Из этого следует, что тег import является простым и распространенным способом для
доступа к URL-ресурсам, чье содержимое может быть включено в JSP-страницу и/или
обработано в ней. Например, в разделе XML-теги import используется для чтения XML-
документа, содержащего информацию о книге, а также присваивания содержимого
переменной области действия xml:
Тег param аналогичный тегу jsp:param (см. Элемент jsp:param) может использоваться
вместе с import для определения параметров запроса.
В разделе Отслеживание сессии мы обсуждали то, как приложение должно перезаписывать
URL-адреса для запуска механизма отслеживания сессии каждый раз, когда клиент
запрещает использование файлов cookie. Вы можете использовать тег url для перезаписи
URL-адресов, возвращаемых из JSP-страницы. Тег включает ID сессии в URL только в том
случае, когда файлы cookie отключены. В противном случае он возвращает URL без
изменений. Обратите внимание, что данное свойство требует, чтобы URL-адрес был
относительным. Например, catalog.jsp переписывает URL, используемый для добавления
книги в корзину покупателя, следующим образом:
Web-
Rendered by www.RenderX.com
XML-теги Стр. 503 из 626
<c:url var="url"
value="/catalog" >
<c:param name="Add" value="${bookId}" />
</c:url>
<p><strong><a href="<c:out value='${url}'/>">
Тег redirect отсылает перенаправленный HTTP клиенту. Тег redirect принимает субтеги
param с целью включения параметров в возвращаемый URL.
17.5. XML-теги
Ключевым подходом в работе с XML-документами является возможность осуществления
более легкого доступа к их содержимому. XPath (рекомендуемый W3C с 1999 года)
обеспечивает простой вид записи для определения и выбора объектов в XML-документе.
Набор тегов XML библиотеки JSTL, перечисленный в Таблице 16-4, базируется на XPath
(см. раздел Как функционирует XPath).
Таблица 16-4 XML-теги
Область Функция Теги TLD Префикс
XML Ядро outparseset /jstl-x x
Управление потоками choose when other-
wiseforEachif
Преобразование transform param
Web-
Rendered by www.RenderX.com
Стр. 504 из 626 Стандартная библиотека тегов JavaServer-страниц
Теги out и set соответствуют поведению, описанному в разделе Теги выражений, локального
языка выражений XPath. Тег out оценивает XPath-выражение в текущем контекстном узле
и выводит результат оценки в текущий объект JspWriter.
Тег set оценивает XPath-выражение и устанавливает результат в атрибут области действия
JSP-страницы, определенный атрибутом var.
JSP-страница bookdetails.jsp выбирает элемент-книга, чей атрибут id соответствует
параметру запроса bookId и устанавливает атрибут abook. Затем, тег out выбирает элемент-
название книги и выводит результат.
<x:set var="abook"
select="$applicationScope.booklist/
books/book[@id=$param:bookId]" />
Web-
Rendered by www.RenderX.com
XML-теги Стр. 505 из 626
<h2><x:out select="$abook/title"/></h2>
Как вы могли убедиться, тег x:set хранит внутреннее XML-представление узла, извлеченного
с помощью XPath-выражения. Он не конвертирует выбранный узел в String и не хранит
его. Таким образом, тег x:set прежде всего полезен для хранения частей документов с
целью последующего восстановления.
Если вы желаете хранить String, необходимо в теге c:set использовать тег x:out. Тег x:out
конвертирует узел в String, а затем c:set хранит String, как атрибут области действия.
Например, страница bookdetails.jsp хранит атрибут области действия, содержащий цену,
который позднее направляется в тег fmt. Это выглядит следующим образом:
<c:set var="price">
<x:out select="$abook/price"/>
</c:set>
<h4><fmt:message key="ItemPrice"/>:
<fmt:formatNumber value="${price}" type="currency"/>
Другой вариант, который является более прямым, но требует большего знания XPath
пользователя, предназначен для навязывания узлу типа String вручную, используя функцию
string языка XPath.
<x:forEach var="book"
select="$applicationScope:booklist/books/*">
<tr>
<c:set var="bookId">
<x:out select="$book/@id"/>
</c:set>=
<td bgcolor="#ffffaa">
<c:url var="url"
Web-
Rendered by www.RenderX.com
Стр. 506 из 626 Стандартная библиотека тегов JavaServer-страниц
value="/bookdetails" >
<c:param name="bookId" value="${bookId}" />
<c:param name="Clear" value="0" />
</c:url>
<a href="<c:out value='${url}'/>">
<strong><x:out select="$book/title"/>
</strong></a></td>
<td bgcolor="#ffffaa" rowspan=2>
<c:set var="price">
<x:out select="$book/price"/>
</c:set>
<fmt:formatNumber value="${price}" type="currency"/>
</td>
<td bgcolor="#ffffaa" rowspan=2>
<c:url var="url" value="/catalog" >
<c:param name="Add" value="${bookId}" />
</c:url>
<p><strong><a href="<c:out value='${url}'/>">
<fmt:message key="CartAdd"/> </a>
</td>
</tr>
<tr>
<td bgcolor="#ffffff">
<fmt:message key="By"/><em>
<x:out select="$book/firstname"/>
<x:out select="$book/surname"/></em></td></tr>
</x:forEach>
Web-
Rendered by www.RenderX.com
Теги интернационализации Стр. 507 из 626
<context-param>
<param-name>
javax.servlet.jsp.jstl.fmt.localizationContext
</param-name>
<param-value>messages.BookstoreMessages</param-value>
Web-
Rendered by www.RenderX.com
Стр. 508 из 626 Стандартная библиотека тегов JavaServer-страниц
</context-param>
<h3><fmt:message key="Choose"/></h3>
используется для отображения локализованной цены книги. Обратите внимание на то, что
цена сохраняется в базе данных в долларах, поэтому локализация в некоторой степени
упрощена (тег formatNumber не "подозревает" о валютных курсах). Тег форматирует валюту,
но не конвертирует ее.
Кроме этого доступны и другие аналогичные теги для форматирования дат (formatDate),
и анализа чисел и дат (parseNumber, parseDate). Тег timeZone устанавливает временную
полосу (определенную атрибутом value), которая используется всеми вложенными тегами
formatDate.
В странице receipt.jsp, создается эталонная дата поставки, которая затем форматируется
при помощи тега formatDate:
Web-
Rendered by www.RenderX.com
SQL-теги Стр. 509 из 626
17.7. SQL-теги
JSTL SQL-теги сконструированы для быстрого моделирования и создания простых
приложений. Для производства приложений операции баз данных обычно инкапсулируются
в JavaBean-компоненты.
Таблица 16-7 SQL-теги
Область Функция Теги TLD Префикс
База данных setDataSource /jstl-sql sql
SQL query dateParam param-
transactionupdate
dateParam param
Тег update используется для обновления строки базы данных. Тег transaction используется
для автоматического выполнения последовательности SQL-выражений.
Web-
Rendered by www.RenderX.com
Стр. 510 из 626 Стандартная библиотека тегов JavaServer-страниц
JSP-страница receipt.jsp использует для каждого заказа оба тега, обновляющих хранилище
базы данных. Из-за того, что в корзине покупателя может находиться более одной книги,
тег transaction используется для заключения в него большого количества запросов и
обновлений. Вначале страница устанавливает, является ли достаточным существующее
хранилище, после чего она обновляется.
<sql:query var="books"
sql="select * from PUBLIC.books where id = ?" >
<sql:param value="${bookId}" />
</sql:query>
<jsp:useBean id="inventory"
class="database.BookInventory" />
<c:forEach var="bookRow" begin="0"
items="${books.rowsByIndex}">
<jsp:useBean id="bookRow" type="java.lang.Object[]" />
<jsp:setProperty name="inventory" property="quantity"
value="<%=(Integer)bookRow[7]%>" />
<sql:query var="books"
sql="select * from PUBLIC.books where id = ?" >
Web-
Rendered by www.RenderX.com
SQL-теги Стр. 511 из 626
Web-
Rendered by www.RenderX.com
Стр. 512 из 626 Стандартная библиотека тегов JavaServer-страниц
<sql:query var="books"
dataSource="${applicationScope.bookDS}">
select * from PUBLIC.books where id = ?
<sql:param value="${bid}" />
</sql:query>
<c:forEach var="bookRow" begin="0"
items="${books.rowsByIndex}">
<jsp:useBean id="bid" type="java.lang.String" />
<jsp:useBean id="bookRow" type="java.lang.Object[]" />
Web-
Rendered by www.RenderX.com
Дополнительная информация Стр. 513 из 626
Web-
Rendered by www.RenderX.com
Стр. 514 из 626 Безопасность Web-приложений
Web-
Rendered by www.RenderX.com
Пользователи, группы и роли Стр. 515 из 626
Web-
Rendered by www.RenderX.com
Стр. 516 из 626 Безопасность Web-приложений
<?xml version='1.0'?>
<tomcat-users>
<role rolename="admin"/>
<role rolename="manager"/>
<role rolename="provider"/>
<user username="your_name" password="your_password"
roles="admin,manager,provider"/>
</tomcat-users>
<JWSDP_HOME>/bin/startup.sh ( Unix- )
<JWSDP_HOME>\bin\startup.bat ( Microsoft Windows)
Сценарий загрузки запускает задачу в фоновом режиме, после чего сразу же возвращает
пользователя к командной строке. Для полной загрузки Tomcat загрузочному сценарию
требуется некоторое время.
Примечание: Сценарий загрузки Tomcat выполняется в течение нескольких минут. Для
проверки полной загрузки Tomcat откройте в броузере http://localhost:8080. После появления
заставки Tomcat можно продолжить работу. Если заставка не загружается сразу, подождите
несколько минут, а затем повторите процесс. Если по прошествии нескольких минут
Web-
Rendered by www.RenderX.com
Пользователи, группы и роли Стр. 517 из 626
http://localhost:8080/admin
Web-
Rendered by www.RenderX.com
Стр. 518 из 626 Безопасность Web-приложений
Web-
Rendered by www.RenderX.com
Пользователи, группы и роли Стр. 519 из 626
<?xml version='1.0'?>
<tomcat-users>
<role rolename="admin"/>
<role rolename="user" description="Getting Started
App Security Role"/>
<role rolename="manager"/>
<role rolename="provider"/>
<user username="your_name" password="your_password"
roles="admin,manager,provider"/>
<user username="Duke" password="javarocks"
fullName="Duke the Java Programming wiz"
roles="user"/>
</tomcat-users>
Web-
Rendered by www.RenderX.com
Стр. 520 из 626 Безопасность Web-приложений
2. Выйдите из admintool.
3. Закройте Tomcat.
4. Отредактируйте файл build.properties таким образом, чтобы новые или
модифицированные имя пользователя и пароль совпадали. Подробнее о файле
build.properties читайте в разделе Создание файла BuildProperties.
5. Загрузите Tomcat (дождитесь полной загрузки).
6. Запустите deploytool. Введите имя пользователя и пароль, которому в файле tomcat-
users.xml назначены роли admin и manager, и которые совпадают с именем пользователя
и паролем в файле build.properties.
<JWSDP_HOME>/bin/deploytool
3. В диалоге Set Tomcat Server введите имя пользователя и пароль, которому назначена
роль admin.
4. Выберите или откройте файл WAR Web-приложения, <JWSDP_HOME>/docs/tutorial/exam-
ples/gs/gs.war.
Web-
Rendered by www.RenderX.com
Безопасность Web-ярусов Стр. 521 из 626
Web-
Rendered by www.RenderX.com
Стр. 522 из 626 Безопасность Web-приложений
7. Выберите кнопку Edit под пунктом Get. Перейдите к Web-клиенту (в файле WAR примера
Getting Started им являтся index.jsp). Чтобы закрыть диалог, выберите Add, затем OK.
8. Для добавления роли user к ограничению безопасности выберите кнопку Edit рядом с
полем Authorized Roles. Этим вы определите набор ролей, которым позволено получать
доступ к набору Web-ресурсов.
9. Выберите Import Roles для импорта ролей, добавленных к файлу tomcat-users.xml при
помощи утилиты admintool.
10. Выберите слева роль user. Выберите Add. Роль добавится в список Authorized Roles
List.
11. Нажмите OK. Выбранная роль отобразится в списке Authorized Roles для данного
приложения. Для получения информации о создании пользователей и ролей при помощи
admintool обратитесь к разделу Управление ролями и пользователями.
Теперь, когда ограничения безопасности добавлены в приложение, запустим его для
проверки.
1. Выберите Tools _ Deploy для того, чтобы убедиться, что используется последняя версия
файла WAR. Во всех появляющихся диалогах выбирайте OK.
2. После завершения размещения закройте консоль Deploy.
3. Откройте приложение Getting Started в Web-броузере, используя следующий URL:
http://localhost:8080/GSApp
Web-
Rendered by www.RenderX.com
Безопасность Web-ярусов Стр. 523 из 626
<web-app>
<display-name>GSApp</display-name>
<servlet>
<servlet-name>index</servlet-name>
<display-name>index</display-name>
<jsp-file>/index.jsp</jsp-file>
</servlet>
<session-config>
<session-timeout>30</session-timeout>
</session-config>
<security-constraint>
<web-resource-collection>
<web-resource-name>WRCollection</web-resource-name>
<url-pattern>/index.jsp</url-pattern>
<http-method>GET</http-method>
</web-resource-collection>
<auth-constraint>
<role-name>user</role-name>
</auth-constraint>
<user-data-constraint>
<transport-guarantee>NONE</transport-guarantee>
</user-data-constraint>
</security-constraint>
<login-config>
<auth-method>BASIC</auth-method>
<realm-name></realm-name>
</login-config>
<security-role>
<role-name>admin</role-name>
</security-role>
<security-role>
<description>Getting Started App User</description>
<role-name>user</role-name>
</security-role>
<security-role>
<role-name>manager</role-name>
</security-role>
<security-role>
<role-name>provider</role-name>
Web-
Rendered by www.RenderX.com
Стр. 524 из 626 Безопасность Web-приложений
</security-role>
</web-app>
Web-
Rendered by www.RenderX.com
Безопасность Web-ярусов Стр. 525 из 626
Web-
Rendered by www.RenderX.com
Стр. 526 из 626 Безопасность Web-приложений
Web-
Rendered by www.RenderX.com
Безопасность EIS-ярусов Стр. 527 из 626
Web-
Rendered by www.RenderX.com
Стр. 528 из 626 Безопасность Web-приложений
Web-
Rendered by www.RenderX.com
Установка и настройка поддержки SSL для Tomcat Стр. 529 из 626
Web-
Rendered by www.RenderX.com
Стр. 530 из 626 Безопасность Web-приложений
Примечание: Для того чтобы получить имя .keystore, Tomcat производит поиск файла
keystore в "домашней" директории компьютера, на котором запущен Tomcat.
Web-
Rendered by www.RenderX.com
Установка и настройка поддержки SSL для Tomcat Стр. 531 из 626
Web-
Rendered by www.RenderX.com
Стр. 532 из 626 Безопасность Web-приложений
Web-
Rendered by www.RenderX.com
Установка и настройка поддержки SSL для Tomcat Стр. 533 из 626
7. В поле Port введите 8443 (или тот порт, который требуется). Это определяет номер
порта TCP/IP, который Tomcat будет использовать для безопасных соединений.
8. Введите Keystore Name и Keystore Password, если вы создали файл keystore с именем
отличным от .keystore, или же если .keystore находится в директории, отличной от
"домашней" директории машины, на которой запущен Tomcat, или пароль имеет
значение, отличное от changeit. Если вы используете ожидаемые значения, оставьте
это поле пустым.
9. "Домашней" директорией обычно является /home/user_name в системах Unix и Linux,
и C:\Documents and Settings\user_name в системах Microsoft Windows.
10. Выберите Save для сохранения нового элемента Connector для данной сессии.
11. Выберите Commit Changes для записи информации о новом элементе Connector в
файл server.xml. Коннектор будет доступен при следующей перезагрузке Tomcat.
Для того чтобы просмотреть и/или отредактировать новый элемент Connector, разверните
узел Service (Java Web Services Developer Pack) и выберите Connector (8443).
<!--
<Connector
className="org.apache.coyote.tomcat4.CoyoteConnector"
port="8443" minProcessors="5"
maxProcessors="75"
enableLookups="false"
acceptCount="10"
connectionTimeout="60000" debug="0"
scheme="https" secure="true">
<Factory
className="org.apache.coyote.tomcat4.
CoyoteServerSocketFactory"
clientAuth="false" protocol="TLS" />
Web-
Rendered by www.RenderX.com
Стр. 534 из 626 Безопасность Web-приложений
</Connector>
-->
https://localhost:8443/
Протокол https в данном URL указывает на то, что броузер использует SSL-протокол. Порт
8443,является портом, в котором в предыдущем разделе был создан SSL-Connector.
При первой загрузке пользователем данного приложения отобразится диалог New Site
Certificate. Выберите Next для прохождения ряда диалогов New Site Certificate, выберите
Finish, когда достигнете последнего диалога.
Web-
Rendered by www.RenderX.com
Устранение неисправностей Стр. 535 из 626
Web-
Rendered by www.RenderX.com
Стр. 536 из 626 Приложение Coffee Break
Web-
Rendered by www.RenderX.com
Обзор приложения Coffee Break Стр. 537 из 626
При запуске, а также по требованию сервер Coffee Break опрашивает поставщиков кофе
с целью получения от них информации о наличии в продаже разных сортов кофе и о его
ценах.
1. Сервер Coffee Break использует для связи с одним из поставщиков обмен сообщениями
JAXM.
2. Необходимыми условиями для осуществления обмена сообщениями JAXM в виде
запрос-ответ являются работа с поставщиком и наличие уже происходивших ранее
сделок. Обе стороны соглашаются обмениваться четырьмя видами XML-сообщений и
должны установить определения DTD для каждого из них.
3. Сервер Coffee Break использует JAXR для отправки запросов с целью поиска
поставщиков кофе, которые поддерживают JAX-RPC для сервера реестра.
4. Сервер Coffee Break запрашивает прайс-листы у каждого из поставщиков кофе. Сервер
осуществляет соответствующую процедуру удаленного вызова и ожидает ответа,
который JavaBean-компонент представляет в виде прайс-листа. Поставщик JAXM
возвращает прайс-листы в виде XML-документов.
5. Получив ответы, сервер Coffee Break обрабатывает прайс-листы из JavaBean-
компонентов, возвращенных от поставщиков.
6. Сервер Coffee Break создает локальную базу данных поставщиков.
7. После того как заказ осуществлен, одному или более поставщикам отправляются
подзаказы, при этом используется протокол, предпочитаемый поставщиком.
Web-
Rendered by www.RenderX.com
Стр. 538 из 626 Приложение Coffee Break
package com.sun.cb;
import java.rmi.Remote;
import java.rmi.RemoteException;
Web-
Rendered by www.RenderX.com
Служба JAX-RPC поставщика Стр. 539 из 626
Date tomorrow =
com.sun.cb.DateHelper.addDays(new Date(), 1);
ConfirmationBean confirmation =
new ConfirmationBean(order.getId(), tomorrow);
return confirmation;
}
PriceItemBean[] priceItems =
PriceLoader.loadItems(propsName);
PriceListBean priceList =
new PriceListBean(today, endDate, priceItems);
Web-
Rendered by www.RenderX.com
Стр. 540 из 626 Приложение Coffee Break
return priceList;
}
package com.sun.cb;
import javax.xml.registry.*;
import java.util.ResourceBundle;
import java.io.*;
ResourceBundle registryBundle =
ResourceBundle.getBundle
("com.sun.cb.CoffeeRegistry");
String queryURL =
registryBundle.getString("query.url");
Web-
Rendered by www.RenderX.com
Служба JAX-RPC поставщика Стр. 541 из 626
String publishURL =
registryBundle.getString("publish.url");
String username =
registryBundle.getString("registry.username");
String password =
registryBundle.getString("registry.password");
String endpoint = registryBundle.getString("endpoint");
String keyFile = registryBundle.getString("key.file");
try {
FileWriter out = new FileWriter(keyFile);
out.write(key);
out.flush();
out.close();
} catch (IOException ex) {
System.out.println(ex.getMessage());
}
}
Web-
Rendered by www.RenderX.com
Стр. 542 из 626 Приложение Coffee Break
rs = connection.getRegistryService();
blcm = rs.getBusinessLifeCycleManager();
bqm = rs.getBusinessQueryManager();
В виду того, что для выполнения публикации данных требуется подтверждение пароля,
для получения мандата безопасности используются аргументы username и password:
PasswordAuthentication passwdAuth =
new PasswordAuthentication(username,
password.toCharArray());
Set creds = new HashSet();
creds.add(passwdAuth);
connection.setCredentials(creds);
ResourceBundle bundle =
ResourceBundle.getBundle("com.sun.cb.CoffeeRegistry");
//
Organization org =
blcm.createOrganization(bundle.getString("org.name"));
Web-
Rendered by www.RenderX.com
Служба JAX-RPC поставщика Стр. 543 из 626
InternationalString s =
blcm.createInternationalString
(bundle.getString("org.description"));
org.setDescription(s);
// ,
org.setPrimaryContact(primaryContact);
http://localhost:8080/jaxrpc-coffee-supplier/jaxrpc/SupplierIF
Web-
Rendered by www.RenderX.com
Стр. 544 из 626 Приложение Coffee Break
//
Collection serviceBindings = new ArrayList();
ServiceBinding binding = blcm.createServiceBinding();
is = blcm.createInternationalString
(bundle.getString("service.binding"));
binding.setDescription(is);
try {
binding.setAccessURI(endpoint);
} catch (JAXRException je) {
throw new JAXRException("Error: Publishing this " +
"service in the registry has failed because " +
"the service has not been installed on Tomcat.");
}
serviceBindings.add(binding);
//
service.addServiceBindings(serviceBindings);
// ,
-
services.add(service);
org.addServices(services);
Web-
Rendered by www.RenderX.com
Служба JAX-RPC поставщика Стр. 545 из 626
И, наконец, метод возвращает строку id так, что программа OrgPublisher может сохранить
ее в файл для использования программой OrgRemover.
package com.sun.cb;
import java.util.ResourceBundle;
import javax.xml.registry.*;
import javax.xml.registry.infomodel.Key;
import java.io.*;
Web-
Rendered by www.RenderX.com
Стр. 546 из 626 Приложение Coffee Break
ResourceBundle registryBundle =
ResourceBundle.getBundle
("com.sun.cb.CoffeeRegistry");
String queryURL =
registryBundle.getString("query.url");
String publishURL =
registryBundle.getString("publish.url");
String username =
registryBundle.getString("registry.username");
String password =
registryBundle.getString("registry.password");
String keyFile = registryBundle.getString("key.file");
try {
FileReader in = new FileReader(keyFile);
char[] buf = new char[512];
while (in.read(buf, 0, 512)>= 0) { }
in.close();
keyStr = new String(buf).trim();
} catch (IOException ex) {
System.out.println(ex.getMessage());
}
Web-
Rendered by www.RenderX.com
Служба JAXM поставщика Стр. 547 из 626
Web-
Rendered by www.RenderX.com
Стр. 548 из 626 Приложение Coffee Break
JWSDP_HOME/docs/tutorial/examples/cb/jaxm/src/com/sun/cb
Web-
Rendered by www.RenderX.com
Служба JAXM поставщика Стр. 549 из 626
Таким образом, программный код клиента состоит из двух основных задач. Первая -
создание и отправка запроса, вторая - извлечение содержимого из ответа. Данные задачи
обрабатываются классами PriceListRequest и OrderRequest.
SOAPConnectionFactory scf =
SOAPConnectionFactory.newInstance();
SOAPConnection con = scf.createConnection();
MessageFactory mf = MessageFactory.newInstance();
SOAPMessage msg = mf.createMessage();
Файл price-list.dtd задает, что самым крайним элементом тела является элемент request-
prices, содержащий элемент request. Текстовый узел, добавленный к request является
текстом отправленного запроса. У каждого нового элемента, добавленного к сообщению,
должен быть объект Name (необходимый для его идентификации), который создается при
помощи метода createName класса Envelope. Представленные далее строки программного
кода создают крайний элемент объекта body в объекте SOAPBody. Первым элементом,
созданным в объекте SOAPBody всегда является объект SOAPBodyElement.
Web-
Rendered by www.RenderX.com
Стр. 550 из 626 Приложение Coffee Break
"RequestPrices", "http://sonata.coffeebreak.com");
SOAPBodyElement requestPrices =
body.addBodyElement(bodyName);
msg.saveChanges();
После выполнения метода call, Tomcat выполняет сервлет PriceListServlet. Данный сервлет
создает и возвращает объект SOAPMessage, чьим содержимым является прайс-лист JAXM
поставщика (PriceListServlet обсуждается в разделе Возвращение прайс-листа.) Tomcat
"знает" о том, что необходимо выполнить сервлет PriceListServlet, так как файл web.xml,
находящийся в директории <JWSDP>/docs/tutorial/examples/cb/jaxm/web/ отображает
заданную конечную точку для данного сервлета.
Web-
Rendered by www.RenderX.com
Служба JAXM поставщика Стр. 551 из 626
Программный код создает пустой объект Vector, который будет содержать элементы coffee-
name и price, извлеченные из response. Затем код использует response для доступа к его
объекту SOAPBody, который содержит содержимое сообщения. Обратите внимание на
то, что отдельный доступ к объекту SOAPEnvelope не производится, в силу того, что он
не является необходимым для создания объектов Name, как это было в предыдущем
разделе.
Объект it2 объекта Iterator содержит вложенные элементы объекта bodyEl, который
представляет элементы coffee. Вызов метода next к объекту it2 позволяет получить первый
элемент coffee в объекте bodyEl. До тех пор, пока объект it2 содержит другой элемент,
метод next будет возвращать следующий элемент coffee.
Web-
Rendered by www.RenderX.com
Стр. 552 из 626 Приложение Coffee Break
В последнем фрагменте кода к ArrayList priceItems добавляется название кофе и его цена
(в виде PriceListItem), после чего они попарно выводятся в отдельную строку. В заключение
он конструирует и возвращает PriceListBean.
Web-
Rendered by www.RenderX.com
Служба JAXM поставщика Стр. 553 из 626
SOAPConnectionFactory scf =
SOAPConnectionFactory.newInstance();
SOAPConnection con = scf.createConnection();
MessageFactory mf = MessageFactory.newInstance();
SOAPMessage msg = mf.createMessage();
childName = envelope.createName("last-name");
SOAPElement lastName = customer.addChildElement(childName);
lastName.addTextNode(orderBean.getCustomer().
Web-
Rendered by www.RenderX.com
Стр. 554 из 626 Приложение Coffee Break
getLastName());
childName = envelope.createName("first-name");
SOAPElement firstName = customer.addChildElement(childName);
firstName.addTextNode(orderBean.getCustomer().
getFirstName());
childName = envelope.createName("phone-number");
SOAPElement phoneNumber = customer.addChildElement(childName);
phoneNumber.addTextNode(orderBean.getCustomer().
getPhoneNumber());
childName = envelope.createName("email-address");
SOAPElement emailAddress =
customer.addChildElement(childName);
emailAddress.addTextNode(orderBean.getCustomer().
getEmailAddress());
Элемент address, добавляемый далее, содержит вложенные элементы street (улица), city
(город), state (штат) и zip code (почтовый индекс). Данная информация извлечена из
компонента Address, объекта OrderBean.
childName = envelope.createName("address");
SOAPElement address = order.addChildElement(childName);
childName = envelope.createName("street");
SOAPElement street = address.addChildElement(childName);
street.addTextNode(orderBean.getAddress().getStreet());
childName = envelope.createName("city");
SOAPElement city = address.addChildElement(childName);
city.addTextNode(orderBean.getAddress().getCity());
childName = envelope.createName("state");
SOAPElement state = address.addChildElement(childName);
state.addTextNode(orderBean.getAddress().getState());
childName = envelope.createName("zip");
SOAPElement zip = address.addChildElement(childName);
Web-
Rendered by www.RenderX.com
Служба JAXM поставщика Стр. 555 из 626
zip.addTextNode(orderBean.getAddress().getZip());
Элемент line-item содержит три вложенных элемента: coffeeName, poundsи price. Данная
информация извлекается из списка LineItems, содержащегося в объекте OrderBean.
childName = envelope.createName("line-item");
SOAPElement lineItem =
order.addChildElement(childName);
childName = envelope.createName("coffeeName");
SOAPElement coffeeName =
lineItem.addChildElement(childName);
coffeeName.addTextNode(lib.getCoffeeName());
childName = envelope.createName("pounds");
SOAPElement pounds =
lineItem.addChildElement(childName);
pounds.addTextNode(lib.getPounds().toString());
childName = envelope.createName("price");
SOAPElement price =
lineItem.addChildElement(childName);
price.addTextNode(lib.getPrice().toString());
// childName = envelope.createName("total");
SOAPElement total =
order.addChildElement(childName);
total.addTextNode(orderBean.getTotal().toString());
}
Web-
Rendered by www.RenderX.com
Стр. 556 из 626 Приложение Coffee Break
SOAPElement ID = (SOAPElement)bodyIt2.next();
String id = ID.getValue();
SimpleDateFormat df = new
SimpleDateFormat("EEE MMM dd HH:mm:ss z yyyy");
Date date = df.parse(shippingDate);
ConfirmationBean cb = new ConfirmationBean(id, date);
Web-
Rendered by www.RenderX.com
Служба JAXM поставщика Стр. 557 из 626
MessageFactory msgFactory;
Каждый сервлет имеет метод init. Данный метод init инициализирует сервлет с информацией
о конфигурации, которую передает для него Tomcat. Затем он просто инициализирует
объект msgFactory при помощи реализации (используемой по-умолчанию) класса
MessageFactory.
Web-
Rendered by www.RenderX.com
Стр. 558 из 626 Приложение Coffee Break
// HTTP- .
InputStream is = req.getInputStream();
// HTTP-
// SOAPMessage
SOAPMessage msg = msgFactory.createMessage(headers, is);
Далее в коде объявляется объект reply объекта SOAPMessage и заполняет его путем
вызова метода onMessage.
Если в reply что-то содержится, его содержимое сохраняется, значение статуса resp
устанавливается как OK, а заголовки и содержимое reply записываются в resp. Если reply
пуст, статус resp будет указывать на отсутствие содержимого.
Web-
Rendered by www.RenderX.com
Служба JAXM поставщика Стр. 559 из 626
if (reply != null) {
// saveChanges, . .
// MimeHeaders
HTTP- .
// MimeHeaders
.
if (reply.saveRequired()) {
reply.saveChanges();
}
resp.setStatus(HttpServletResponse.SC_OK);
putHeaders(reply.getMimeHeaders(), resp);
// .
OutputStream os = resp.getOutputStream();
reply.writeTo(os);
os.flush();
} else
resp.setStatus(HttpServletResponse.SC_NO_CONTENT);
Web-
Rendered by www.RenderX.com
Стр. 560 из 626 Приложение Coffee Break
while (enum.hasMoreElements()) {
String headerName = (String)enum.nextElement();
String headerValue = req.getHeader(headerName);
return headers;
}
Web-
Rendered by www.RenderX.com
Служба JAXM поставщика Стр. 561 из 626
Web-
Rendered by www.RenderX.com
Стр. 562 из 626 Приложение Coffee Break
message.saveChanges();
} catch(Exception e) {
e.printStackTrace();
}
return message;
}
}
Web-
Rendered by www.RenderX.com
Служба JAXM поставщика Стр. 563 из 626
try {
// orderID
// orderID
//
confirmation = fac.createMessage();
SOAPPart sp = confirmation.getSOAPPart();
SOAPEnvelope env = sp.getEnvelope();
SOAPBody sb = env.getBody();
Name newBodyName = env.createName("confirmation",
"Confirm", "http://sonata.coffeebreak.com");
SOAPBodyElement confirm =
sb.addBodyElement(newBodyName);
// orderID
Web-
Rendered by www.RenderX.com
Стр. 564 из 626 Приложение Coffee Break
= env.createName("ship-date");
SOAPElement shipDate =
confirm.addChildElement(shipDateName);
confirmation.saveChanges();
Web-
Rendered by www.RenderX.com
Сервер Coffee Break Стр. 565 из 626
19.4.1. JSP-страницы
19.4.1.1. orderForm
Форма orderForm отображает текущее содержимое корзины покупателя. При первом
запросе страницы, количество всего кофе в заказе равняется нулю. Каждый раз, когда
покупатель заносит кофе в корзину и нажимает кнопку Update, запрос заносится в orderForm.
Сервлет Dispatcher обновляет значения в корзине покупателя, которые затем отображаются
заново в orderForm. Когда процесс заказа завершен, покупатель направляется на страницу
checkoutForm путем открытия ссылки Checkout.
19.4.1.2. checkoutForm
Форма checkoutForm используется для сбора информации для покупателя о доставке и
об оплате. После нажатия кнопки Submit запрос заносится в страницу checkoutAck. Однако
он вначале обрабатывается при помощи Dispatcher, который вызывает метод validate
компонента checkoutFormBean. Если проверка не прошла успешно, возвращается страница
checkoutForm с предупреждениями об ошибке в каждом поле, где она была допущена.
Если проверка подтверждена, checkoutFormBean подтверждает подзаказы для каждого
поставщика и сохраняет результат в JavaBean-компоненте OrderConfirmations области
действия запроса, а управление передается странице checkoutAck.
19.4.1.3. checkoutAck
Форма checkoutAck попросту отображает содержимое JavaBean-компонента OrderConfir-
mations, который является списком подзаказов, содержащихся в заказе, и дат поставки
для каждого подзаказа.
19.4.2. JavaBean-компоненты
19.4.2.1. RetailPriceList
RetailPriceList - список позиций прайс-листа. Позиция прайс-листа содержит название кофе,
оптовую цену за фунт, розничную цену за фунт и название поставщика. Эти данные
используются в двух целях: они содержат прайс-лист, представленный конечному
пользователю, а также используются компонентом CheckoutFormBean, когда он создает
подзаказы, передающиеся поставщикам кофе.
Вначале для определения конечных точек службы JAX-RPC выполняется поиск JAXR.
Затем для получения прайс-листа на кофе запрашивается каждая служба JAX-RPC. И
наконец, для той же цели запрашивается служба JAXM. Оба прайс-листа комбинируются,
и розничная цена за фунт определяется путем добавления наценки в 35% от оптовой
цены.
Web-
Rendered by www.RenderX.com
Стр. 566 из 626 Приложение Coffee Break
19.4.2.2. ShoppingCartItem
ShoppingCart является списком позиций в корзине покупателя. В каждой позиции содержится
розничная цена товара, количество фунтов товара и итоговая стоимость.
19.4.2.3. OrderConfirmation
OrderConfirmations является списком объектов подтверждения заказа. Подтверждение
заказа содержит объекты заказа и его подтверждение, как уже обсуждалось в разделе
Интерфейс службы.
19.4.2.4. CheckoutFormBean
CheckoutFormBean проверяет завершенность информации, введенной в checkoutForm.
Если информация неполная, компонент порождает сообщения об ошибке, а Dispatcher
заново отображает страницу checkoutForm с соответствующими сообщениями об ошибках.
Если информация полная, из корзины покупателя конструируется запросы заказа, а
информация предоставляемая checkoutForm отправляется каждому поставщику. При
получении каждого подтверждения, создается подтверждение заказа, которое затем
добавляется к OrderConfirmations.
if (allOk) {
String orderId = CCNumber;
for(Iterator d = rpl.getDistributors().iterator();
d.hasNext(); ) {
String distributor = (String)d.next();
System.out.println(distributor);
ArrayList lis = new ArrayList();
BigDecimal price = new BigDecimal("0.00");
BigDecimal total = new BigDecimal("0.00");
for(Iterator c = cart.getItems().iterator();
c.hasNext(); ) {
ShoppingCartItem sci = (ShoppingCartItem) c.next();
if ((sci.getItem().getDistributor()).
equals(distributor) &&
sci.getPounds().floatValue()> 0) {
price = sci.getItem().
getWholesalePricePerPound().
multiply(sci.getPounds());
Web-
Rendered by www.RenderX.com
Построение, установка и исполнение приложения Стр. 567 из 626
total = total.add(price);
LineItemBean li = new LineItemBean(
sci.getItem().getCoffeeName(), sci.getPounds(),
sci.getItem().getWholesalePricePerPound());
lis.add(li);
}
}
if (!lis.isEmpty()) {
OrderBean order = new OrderBean(orderId,
customer, lis, total, address);
String JAXMOrderURL =
"http://localhost:8080/
jaxm-coffee-supplier/orderCoffee";
if (distributor.equals(JAXMOrderURL)) {
OrderRequest or = new OrderRequest(JAXMOrderURL);
confirmation = or.placeOrder(order);
} else {
OrderCaller ocaller = new OrderCaller(distributor);
confirmation = ocaller.placeOrder(order);
}
OrderConfirmation oc = new OrderConfirmation(order,
confirmation);
ocs.add(oc);
}
}
}
19.4.3. RetailPriceListServlet
RetailPriceListServlet отвечает на запросы для перезагрузки прайс-листа посредством URL
/loadPriceList. Он просто создает новый RetailPriceList и новый ShoppingCart.
Пока сервлет используется администраторами сервера Coffee Break, он является
защищенным Web-ресурсом. Для загрузки прайс-листа, пользователь должен пройти
аутентификацию (используя базовую аутентификацию) и быть в роли admin.
Web-
Rendered by www.RenderX.com
Стр. 568 из 626 Приложение Coffee Break
run-jaxr-publish:
[echo] Running OrgPublisher.
[echo] Note: Remember to start the registry server before running
this program.
[java] Created connection to registry
[java] Got registry service, query manager, and life cycle
manager
[java] Established security credentials
[java] Organization saved
Web-
Rendered by www.RenderX.com
Построение, установка и исполнение приложения Стр. 569 из 626
5. Можно проверить корректность установки службы JAX-RPC, запустив одну из или обе
тестовые программы: выполните ant run-test-price или ant run-test-order. При запуске
ant run-test-price вы должны увидеть следующее:
run-test-price:
run-test-client:
[java] 05/21/02 06/20/02
[java] Kona 6.50
[java] French Roast 5.00
[java] Wake Up Call 5.50
[java] Mocca 4.00
Web-
Rendered by www.RenderX.com
Стр. 570 из 626 Приложение Coffee Break
http://localhost:8080/cbserver/orderForm
Web-
Rendered by www.RenderX.com
Построение, установка и исполнение приложения Стр. 571 из 626
Web-
Rendered by www.RenderX.com
Стр. 572 из 626 Утилита администрирования Tomcat
Web-
Rendered by www.RenderX.com
Запуск admintool Стр. 573 из 626
admintool могут быть сохранены независимо, то есть изменения остаются при перезапуске
Tomcat или они могут быть сохранены только для текущей сессии.
<JWSDP_HOME>/bin/startup.sh (
Unix- )
<JWSDP_HOME>\bin\startup ( Microsoft Windows)
2. Запустите Web-броузер.
3. В Web-броузере откройте следующий URL:
http://localhost:8080/admin
Web-
Rendered by www.RenderX.com
Стр. 574 из 626 Утилита администрирования Tomcat
<JWSDP_HOME>/bin/shutdown.sh ( Unix- )
<JWSDP_HOME>\bin\shutdown ( Microsoft Windows)
Web-
Rendered by www.RenderX.com
Настройка Tomcat Стр. 575 из 626
В этом документе нет описания того, какие конфигурации должны быть использованы для
выполнения специфических задач. Для получения информации подобного рода обратитесь
к одному из документов, указанных ниже:
• Class Loader How-To. В данном документе обсуждаются решения, которые должны
принимать разработчики и разместители приложений, определяя, где помещать классы
и исходные файлы, чтобы сделать их доступными для Web-приложений. Документ
находится в файле: <JWSDP_HOME>/docs/tomcat/class-loader-howto.html.
• Здесь обсуждается настройка JNDI-ресурсов, Tomcat Standard Resource Factories, JDBC
Data Sources, и Custom Resource Factories. Документ находится в файле:
<JWSDP_HOME>/docs/tomcat/jndi-resources-howto.html.
• Manager Application How-To. Этот документ описывает использование менеджера
приложений для размещения нового Web-приложения, сворачивания существующего
приложения или перезагрузки существующего приложения без закрытия и перезагрузки
Tomcat. Документ находится здесь: <JWSDP_HOME>/docs/tomcat/manager-howto.html.
• Proxy Support How-To. В документе обсуждается запуск вне прокси сервера (или если
web-сервер настроен так, что ведет себя как прокси-сервер). Частным образом в
документе описывается, как управлять значениями, возвращенными вызовами из Web-
приложений, запрашиваюих имя сервера и номер порта, в который был направлен
запрос. Вы можете найти этот документ в файле<JWSDP_HOME>/docs/tomcat/proxy-
howto.html.
• Realm Configuration How-To. В данном документе обсуждается то, как настроить Tomcat
для поддержки безопасности, управляемой контейнером, путем соединения с
существующей базой данных имен пользователей, паролей и ролей пользователей.
Он находится в файле <JWSDP_HOME>/docs/tomcat/realm-howto.html.
• Security Manager How-To. В документе обсуждается использование SecurityManager при
работе с Tomcat для защиты вашего сервера от неавторизированных сервлетов, JSP-
страниц, JSP-компонентов и библиотек тэгов. Вы можете найти его в файле:
<JWSDP_HOME>/docs/tomcat/security-manager-howto.html.
• SSL Configuration How-To. В нем обсуждается вопрос установки и настройки поддержки
протокола SSL для Tomcat. Настройка поддержки SSL для Tomcat с использованием
Java WSDP обсуждается в разделе Установка и настройка поддержки SSL для Tomcat.
Документация Tomcat, которая находится в файле <JWSDP_HOME>/docs/tomcat/ssl-
howto.html, также обсуждает эту тему, однако, информация в данном руководстве
является более свежей по сравнению с версией Tomcat, поставляемой с Java WSDP.
Web-
Rendered by www.RenderX.com
Стр. 576 из 626 Утилита администрирования Tomcat
Web-
Rendered by www.RenderX.com
Настройка элементов Service Стр. 577 из 626
Для каждого определенного элемента Service можно создать или удалить следующие
элементы:
• Элементы Connector, символизирующие интерфейс между службой и внешними
клиентами, которые отправляют запросы и получают от нее ответы. Для получения
более детальной информации обратитесь к разделу Настройка элементов Connector.
• Элементы Host, символизирующие виртуальный хост, который ассоциируется с сетевым
именем сервера (к примеру, www.mycompany.com), являющимся частью сервера, на
котором запущен Tomcat. Для получения более детальной информации обратитесь к
разделу Настройка элементов Host.
• Элементы Logger, символизирующие адресата для записи журнала, отладки и сообщений
об ошибках (включая содержимое стека) для Tomcat (Engine, Host или Context). Для
получения детальной информации обратитесь к разделу Настройка элементов Logger.
• Элементы Realm, символизирующие базу данных имен пользователей, паролей и ролей,
назначенных этим пользователям. Подробнее читайте об этом в разделе Настройка
элементов Realm.
• Элементы Valve, символизирующие компонент, который будет включен в поток обработки
запроса для ассоциированного с ним контейнера (Engine, Host, или Context). Более
подробная информация находится в документе Настройка элементов Valve.
Web-
Rendered by www.RenderX.com
Стр. 578 из 626 Утилита администрирования Tomcat
Web-
Rendered by www.RenderX.com
Настройка элементов Service Стр. 579 из 626
Атрибут Описание
Default Buffer Size Размер буфера (в байтах) для входящих потоков, созданных
данным коннектором. По-умолчанию обеспечивается буфер,
размером 2048 байт.
Enable DNS Lookups Если вы желаете, чтобы при помощи вызовов к методу
request.getRemoteHost() осуществлялся поиск в DNS с целью
возвращения имени хоста удаленного клиента, установите
в качестве значения аттрибута True. В противном случае,
для того, чтобы пропустить поиск в DNS и ввести напрямую
IP адрес в форму String (это позволит увеличить
производительность) установите значение False.
IP Address Определяет, какой адрес для серверов, имеющих более чем
один адрес IP, будет использоваться для прослушивания
заданного порта. По-умолчанию данный порт будет
использоваться на всех адресах IP, связанных с сервером.
Port Number Номер порта TCP, на котором Connector создаст сокет
сервера и будет ожидать входящие соединения. Ваша
операционная система позволит только одному приложению
сервера прослушивать отдельный порт на отдельном IP-
адресе.
Redirect Port Number Номер порта, в который Tomcat автоматически будет
перенаправлять запрос, если Connector поддерживает
запросы через небезопасные соединения, а также получать
запрос, для которого соответствующие ограничения
безопасности требуют передачу посредством протокола SSL.
Minimum Количество потоков запросов для обработки, которые будут
созданы после запуска данного коннектора. Значение данного
атрибута должно быть меньше значения атрибута Maximum.
По-умолчанию оно равно 5.
Maximum Максимальное количество запросов для обработки,
создаваемых данным коннектором. Атрибут также определяет
максимальное количество одновременных запросов, которые
могут быть обработаны. Если значение не определено, по-
умолчанию оно установлено на 75.
Таблице A-5
Таблица A-5 Атрибуты HTTPS
Атрибут Описание
Client Authentication Если вы хотите, чтобы перед установкой соединения стэк
SSL требовал правильной цепочки сертификатов от клиента,
установите значение True. В противном случае, установите
False (определенное по-умолчанию), при этом цепочка
сертификатов не потребуется, пока клиент не запросит доступ
к ресурсу, защищенному ограничениями безопасности, для
чего потребуется его аутентификация.
Web-
Rendered by www.RenderX.com
Стр. 580 из 626 Утилита администрирования Tomcat
Атрибут Описание
Keystore Filename Путь и имя загружаемого файла ключей в котором хранится
сертификат клиента. По-умолчанию, именем файла является
.keystore. Он находится в домашней директории пользователя
операционной системы, который запустил Tomcat. Если вы
используете для имени файла и его пути значения,
определенные по-умолчанию, оставьте это поле пустым.Если
же вы определии имя файла ключей без назначения пути к
нему, утилита admintool будет искать его в директории
JWSDP_HOME>.
Keystore Password Пароль, используемый для получения доступа к сертификату
сервера из заданного файла ключей. По-умолчанию
установлено значение changeit.
Примечание: При использовании коннектора SSL, для создания файла ключей необходимо
использовать утилиту keytool. Если вы сгенерировали файл ключей с именем .keystore и
паролем changeit (определенными по-умолчанию) в домашней директории пользователя,
можно оставить атрибуты Keystore Filename и Keystore Password пустыми. Когда эти два
свойства не определены, admintool будет искать файл ключей со значениями имени и
пароля, установленными по-умолчанию (соответственно .keystore и changeit), в директории,
определенной по-умолчанию (см. выше). Если же вы опредилили имя файла ключей, не
указав пути к нему, admintool будет искать файл в директории <JWSDP_HOME>. В разделе
Установка и настройка поддержки SSL для Tomcat содержится детальная информация по
установке коннектора HTTPS.
Web-
Rendered by www.RenderX.com
Настройка элементов Service Стр. 581 из 626
3. Выберите для редактирования Host или любой из элементов: Contexts, Valves, Loggers
или Aliases.
4. Отредактируйте значения в правом окне.
5. Выберите Save для сохранения изменений в данной сессии. Выберите Commit Changes
для сохранения изменений при перезагрузке Tomcat.
Для создания нового элемента Host,
1. В левой панели выберите элемент Service. Настоятельно рекомендуется
модифицировать только службу Java Web Services Developer Pack Service или службу,
которую вы создали.
2. Выберите Create New Host из списка Available Actions.
3. Введите необходимые значения для элемента Host. Для получения детальной
информации по настройкам смотрите раздел Атрибуты элемента Host.
4. Выберите Save для сохранения изменений в данной сессии. Выберите Commit Changes
для сохранения изменений при перезагрузке Tomcat.
Для получения более подробной информации об элементах Host, ознакомьтесь с
документом "Host Container", который находится в файле
<JWSDP_HOME>/docs/tomcat/config/host.html.
Web-
Rendered by www.RenderX.com
Стр. 582 из 626 Утилита администрирования Tomcat
Тем не менее, при запуске одного и того же набора приложений в некоторых случаях
предпочтительнее преобразовывать два или более сетевых имени на одном виртуальном
хосте. Общим примером использования данного сценария может послужить корпоративный
Web-сайт, в котором пользователи должны иметь возможность использовать как
www.mycompany.com так и company.com для доступа к одному и тому же содержимому и
набору приложений.
Tomcat поддерживает виртуальные хосты, являющиеся, множеством комбинаций "хосты
+ доменные имена", отображаемых в одиночный IP. Обычно, каждое имя хоста
отображается на хост сервера Tomcat, к примеру, www.foo.com отображается на localhost,
или www.foo1.com - на localhost1. В некоторых случаях различные имена хостов могут быть
отображены на один и тот же хост, к примеру, www.foo.com и www.foo1.com могут оба
отображаться на localhost. В данной ситуации вы увидите, что оба эти альтернативных
имени ассоциированы с localhost в утилите admintool.
Для использования альтернативных имен сервер DNS должен иметь имена хостов,
зарегистрированные в IP сервера, на котором будет запускаться Tomcat.
To create a new Host alias,
Для создания нового альтернативного имени хоста,
1. В левой панели выберите элемент Host.
2. Из списка Available Actions выберите Create New Alias.
3. Введите имя Alias.
4. Выберите Save для сохранения изменений в данной сессии. Выберите Commit Changes
для сохранения изменений при перезагрузке Tomcat.
Web-
Rendered by www.RenderX.com
Настройка элементов Service Стр. 583 из 626
Web-
Rendered by www.RenderX.com
Стр. 584 из 626 Утилита администрирования Tomcat
Атрибут Описание
Document Base Базовой директорией документа (также известной, как Context
Root) для данного Web-приложения является путь к WAR-
файлу (если данное приложение выполняется
непосредственно из WAR-файла). Можно обозначить
абсолютное имя пути для данной директории или WAR-
файла, или имя пути относительно базовой директории
приложения.
Override Установите значение True для того, чтобы указанные явно
установки в данном элементе Context переопределяли любые
соответствующие установки из элемента DefaultContext,
связанного с вашим хостом. По-умолчанию используются
установки из элемента DefaultContext, а значением атрибута
является False.
Path Путь контекста данного Web-приложения, совпадающего с
началом запрашивамого URI для выбора Web-приложения,
предназначенного для обработки. Все пути контекста в
пределах отдельного хоста должны быть уникальны. Если
вы определяете путь контекста как пустую строку (""), этим
самым вы определяете Web-приложение, используемое по-
умолчанию для данного хоста, которое будет обрабатывать
все запросы, не относящиеся к другим элементам Context.
Reloadable Установите значение True, если вы желаете, чтобы Tomcat
отслеживал изменения в классах /WEB-INF/classes/ и /WEB-
INF/lib и в случае обнаружения изменений автоматически
перезагружал Web-приложение. Данная особенность
чрезвычайно полезна во время разработки приложения,
однако требует больших затрат ресурсов и не рекомендована
к использованию в размещенных приложениях. Для
инициации перезагрузок размещенных приложений по
требованию можно использовать приложение Manager Web.
Значением по-умолчанию является False.
Use Naming Для того чтобы Tomcat мог использовать JNDI InitialContext
для данного Web-приложения, установите значение True
(совместимо с условиями платформы J2EE). Значением по-
умолчанию является False.
Working irectory Путь к временной директории, используемой сервлетами для
временного чтения и записи в пределах соответствующего
Web-приложения. Данная директория будет видима для
сервлетов в Web-приложении при помощи аттрибута
контекста Servlet (типа java.io.File) под названием
javax.servlet.context.tempdir, как описано в спецификации
сервлетов. Если значение не определено, будет
предоставлена подходящая директория
<JWSDP_HOME>/work.
Web-
Rendered by www.RenderX.com
Настройка элементов Service Стр. 585 из 626
Атрибут Описание
Reloadable Установите значение True, если вы желаете, чтобы Tomcat
отслеживал изменения в классах /WEB-INF/classes/ и /WEB-
INF/lib и в случае обнаружения изменений автоматически
перезагружал Web-приложение. Данная особенность
чрезвычайно полезна во время разработки приложения,
однако требует больших затрат ресурсов и не рекомендована
к использованию в размещенных приложениях. Для
инициации перезагрузок размещенных приложений по
требованию можно использовать приложение Manager Web.
Значением по-умолчанию является False.
Свойства Session Manager позволяют вам настраивать менеджер сессии, который будет
использоваться для создания, уничножения и сохранения HTTP-сессий данного Web-
приложения. Обычно стандартной конфигурации менеджера сессии достаточно. Для
настройки элемента Session Manager доступны аттрибуты, представленые в Таблице A-8.
Таблица A-9 Свойства элемента Session Manager
Атрибут Описание
Check Interval Интервал в секундах между проверками сессии данного
менеджера. на предмет истечения Значением по-умолчанию
является 60.
Debug Level Уровень детальности отладки сообщений журнала. Большие
номера означают вывод более детальной информации. Если
не определено, по-умолчанию значение равно нулю (0).
Session ID Initializer Tomcat обеспечивает две стандартные реализации Session
Manager.org.apache.catalina.session.StandardManager хранит
активные сессии. org.apache.catalina.session.PersistentManager
персистентно хранит активные сессии, которые
свопировались (кроме этого сохраняет сессии при
перезагрузке Tomcat) в хранилище, обозначенном
посредством соответствующего вложенного элемента Store.
Кроме обычных операций создания и удаления сессий
PersistentManager способен свопировать активные (но
неиспользуемые) сессии в персистентный механизм
хранилища, равно как и сохранять все сессии в случае
перезагрузок Tomcat. Используемый персистентный механизм
хранилища выбирается из элементов Store, вложенных в
элемент Manager (это необходимо для использования
PersistentManager).
Maximum Active Sessions Максимальное количество активных сессий, которые будут
создаваться данным менеджером. По-умолчанию количество
сессий не ограничено, значением атрибута является -1.
Web-
Rendered by www.RenderX.com
Стр. 586 из 626 Утилита администрирования Tomcat
Web-
Rendered by www.RenderX.com
Настройка элементов Service Стр. 587 из 626
Атрибут Описание
Verbosity Level Уровень словесного наполнения для данного элемента
Logger. Сообщения с уровнем словесного наполнения более
высоким, чем установлено, будут игнорироваться. Доступные
уровни: 0 (только сообщения о фатальных ошибках), 1
(ошибки), 2 (предупреждения), 3 (информация), и 4
(информация об отладке). Если атрибут не установлен, его
значением по-умолчанию является нуль (0) (только
сообщения о фатальных ошибках).
Если вы используете элемент Logger типа FileLogger, вам будет доступна установка
дополнительных атрибутов, как показано в Таблице A-11.
Таблица A-11 Атрибуты элемента Logger типа FileLogger
Атрибут Описание
Directory Абсолютное или относительное имя пути к директории, в
которой создаются log-файлы. Если установлен
относительный путь, он интерпретируется как путь к
директории, в которой установлен Tomcat. Если атрибут не
определен, значением по-умолчанию является logs
(относительно директори, в которую установлен Tomcat).
Prefix Префикс, который будет добавляться к началу каждого имени
log-файла. По-умолчанию значение определено как catalina.
Для того чтобы запретить использование префикса,
установите в качестве значения атрибута строку нулевой
длины.
Suffix Суффикс, добавляемый к концу каждого log-файла. По-
умолчанию значением данного атрибута является .log. Для
того чтобы запретить использование суффикса, установите
в качестве значения атрибута строку нулевой длины.
Timestamp В любом случае, все сообщения журнала будут отмечаться
датой и временем создания. Если вы хотите использовать
отметку о дате, установите значение True. В противном
случае установите значение False.
Web-
Rendered by www.RenderX.com
Стр. 588 из 626 Утилита администрирования Tomcat
4. Выберите Save для сохранения изменений в данной сессии. Выберите Commit Changes
для сохранения изменений при перезагрузке Tomcat.
Элемент Realm может быть создан внутри любого контейнера - Engine, Host или Context.
У каждого из них может быть только один интерфейс элемента Realm. Элементы Realm,
ассоциированные с Engine или Host автоматически наследуются контейнерами более
низкого уровня, пока не будут переназначены явным образом.
Для того что бы создать новый элемент Realm,
1. Выберите службу, хост или контекст, в которых вы желаете создать новый элемент
Realm.
2. Из списка Available Actions выберите опцию Create New Realm. Выберите тип элемента
Realm. Атрибуты могут варьироваться в зависимости от типа элемента Realm, который
вы выбрали.
Существует несколько стандартных реализаций элемента Realm, включая следующие:
• JDBCRealm
Элемент Realm базы данных JDBC для обеспечения поиска имен, паролей и ролей,
ассоциированных с ними, подключает Tomcat к реляционной базе данных, доступ к
которой осуществляется посредством соответствующего драйвера JDBC. Поиск
производится каждый раз, когда он необходим, поэтому изменения в базе данных будут
немедленно отражаться на информации, используемой для аутентификации новых
логинов. Атрибуты для реализации элемента Realm в базе данных JDBC представлены
в разделе Атрибуты JDBCRealm.
• JNDIRealm
Элемент Realm базы данных JDBC для обеспечения поиска имен, паролей и ролей,
ассоциированных с ними, подключает Tomcat к директории LDAP, доступ к которой
осуществляется посредством соответствующего драйвера JNDI. Поиск производится
каждый раз, когда он необходим, поэтому изменения в базе данных будут немедленно
отражаться на информации, используемой для аутентификации новых логинов. Атрибуты
для реализации элемента Realm в базе данных JNDI представлены в разделе Атрибуты
JNDIRealm.
• MemoryRealm
Элемент Realm, базирующийся на использовании памяти (Memory Based), является
простой реализацией элемента Realm, которая считывает XML-файл для конфигурации
действительных пользователей, паролей и ролей. Формат файла и его местонахождение
идентичны тем файлам, которые поддерживаются Tomcat версии 3.x. Данная реализация
предназначена исключительно для организации работы с безопасностью, управляемой
контейнером - она НЕ предназначена для использовании в производстве. По существу,
нет никаких механизмов для модернизации набора пользователей, находящегося в
памяти, когда содержимое основного файла данных подверглось изменениям. Атрибуты
реализации элемента Memory Realm представлены в разделе Атрибуты элемента
MemoryRealm.
• UserDatabaseRealm
UserDatabaseRealm является реализацией элемента Realm, основанной на реализации
UserDatabase, которая доступна через глобальные ресурсы JNDI, настроенные для
Web-
Rendered by www.RenderX.com
Настройка элементов Service Стр. 589 из 626
Web-
Rendered by www.RenderX.com
Стр. 590 из 626 Утилита администрирования Tomcat
Web-
Rendered by www.RenderX.com
Настройка элементов Service Стр. 591 из 626
Атрибут Описание
* User Base Element (userBase) Список, являющийся основой поддерева, содержащего
пользователей. Если не определено, поиск производится в
самом высоком уровне контекста. Данная опция не
применяется при использовании выражения userPattern (User
Pattern). Этот атрибут (userBase) недоступен в утилите
admintool. Смотрите раздел Определение Realm Attributes в
Server.xml для получения информации об установках данного
атрибута.
*User Pattern (userPattern) Выражение поиска LDAP, используующееся при получении
атрибутов отдельного пользователя, с отметкой {0}, где
должно вводиться имя пользователя. Если вы желаете
выбрать отдельную запись, базирующуюся на имени
пользователя, используйте данный атрибут вместо User
Search Pattern. Данный атрибут (userPattern) не доступен в
утилите admintool. Смотрите раздел Определение Realm
Attributes в Server.xml для получения подробной информации
об установках атрибута.
Search User Subtree Установите значение True, если вы используете User Search
Pattern для поиска аутентифицированных пользователей и
вам необходимо найти в поддеревьях элемент, определенный
User Base Element. Установка значения (по-умолчанию) False
приводит к поиску в определенном уровне. Не применяется,
если вы используете выражение User Pattern.
User Password Имя элемента LDAP, содержащего пароль пользователя.
Если вы определили данное значение, JNDIRealm будет
привязываться к директории с использованием значений,
определенных атрибутами Connection Name и Connection
Password и извлекать соответствующий атрибут для
сравнения значений, определенных пользователем, который
прошел аутентификацию. В противном случае, JNDIRealm
будет привязываться к директории, используя имя
пользователя и пароль, определенные пользователем, где
правильная привязка интерпретируется как аутентификация
пользователя.
User Search Pattern Выражение поиска LDAP использующееся при получении
атрибутов отдельного пользователя, с отметкой {0}, где
должно вводится имя пользователя. Используйте данный
атрибут вместо User Pattern для поиска по всей директории
(вместо извлечения отдельной записи) в дополнение к
контролю над атрибутами User Base Element и Search User
Subtree.
Web-
Rendered by www.RenderX.com
Стр. 592 из 626 Утилита администрирования Tomcat
Атрибут Описание
Debug Level Уровень детальности отладки сообщений журнала. Большие
номера означают вывод более детальной информации. Если
не определено, по-умолчанию значение равно нулю (0).
Digest Algorithm Название алгоритма MessageDigest, используемого для
шифрования паролей пользователей, хранящихся в базе
данных. Если не значение определено, подразумевается,
что пароли будут храниться в текстовом виде.
Role Base Element Элемент базовой директории для выполнения поиска
пользовательских ролей.
Role Name Название атрибута директории, извлекаемого при выборе
назначенных ролей для пользователя. Если не определено,
используйте атрибут User Role Name для определения имени
атрибута в списке пользователей, который содержит ноль
или более имен ролей, назначенных данному пользователю.
Role Search Pattern Выражение поиска LDAP, используемое при выборе ролей
для отдельного пользователя, с отметкой {0}, где должно
вводиться действительное имя пользователя. Для получения
подробной информации обратитесь к разделу Значения для
атрибута шаблона.
Search Role Subtree Установите значение True для поиска в поддеревьях
элементов, выбранных выражением Role Search Pattern.
Установите значение False для отмены поиска в поддеревьях.
Значением по умоляанию является False.
User Role Name Имя атрибута директории в записи пользователя, содержащее
ноль или более значений имен ролей, назначенных данному
пользователю. Если атрибут не задан, используйте атрибут
Role Name для определения имени отдельного атрибута,
полученного из индивидуальных записей ролей, связанных
с данным пользователем.
Search User Subtree Установите значение True, если вы используете User Search
Pattern для поиска аутентифицированных пользователей и
вам необходимо найти в поддеревьях элемент, определенный
User Base Element. Установка значения (по-умолчанию) False
приводит к поиску в определенном уровне. Не применяется,
если вы используете выражение User Pattern.
User Password Имя элемента LDAP, содержащего пароль пользователя.
Если вы определили данное значение, JNDIRealm будет
привязываться к директории с использованием значений,
определенных атрибутами Connection Name и Connection
Password и извлекать соответствующий атрибут для
сравнения значений, определенных пользователем, который
прошел аутентификацию. В противном случае, JNDIRealm
будет привязываться к директории, используя имя
пользователя и пароль, определенные пользователем, где
правильная привязка интерпретируется как аутентификация
пользователя.
User Search Pattern Выражение поиска LDAP использующееся при получении
атрибутов отдельного пользователя, с отметкой {0}, где
должно вводится имя пользователя. Используйте данный
атрибут вместо User Pattern для поиска по всей директории
(вместо извлечения отдельной записи) в дополнение к
контролю над атрибутами User Base Element и Search User
Subtree.
User Search Pattern Выражение поиска LDAP использующееся при получении
атрибутов отдельного пользователя, с отметкой {0}, где
должно вводится имя пользователя. Используйте данный
атрибут для поиска по всей директории вместо извлечения
отдельной записи.
Web-
Rendered by www.RenderX.com
Настройка элементов Service Стр. 593 из 626
<Realm className="org.apache.catalina.realm.JNDIRealm"
debug="99"
connectionName="cn=Manager,dc=mycompany,dc=com"
connectionPassword="secret"
connectionURL="ldap://localhost:389"
roleBase="dc=roles,dc=person,dc=net"
roleName="cn"
roleSearch="(uniqueMember={0})"
roleSubtree="false"
userPassword="userPassword"
userPattern="cn={0},dc=mycompany,dc=com"
/>
<Realm className="org.apache.catalina.realm.JNDIRealm"
debug="99"
connectionURL="ldap://localhost:389"
userBase="ou=people,dc=mycompany,dc=com"
userSearch ="(mail={0})"
userRoleName ="memberOf"
Web-
Rendered by www.RenderX.com
Стр. 594 из 626 Утилита администрирования Tomcat
roleBase="ou=groups,dc=mycompany,dc=com"
roleName="cn"
roleSearch="(uniqueMember={0})"
/>
Web-
Rendered by www.RenderX.com
Настройка элементов Service Стр. 595 из 626
Web-
Rendered by www.RenderX.com
Стр. 596 из 626 Утилита администрирования Tomcat
Атрибут Описание
Prefix Префикс, добавляемый к началу каждого имени log-файла.
Ели не определено, значением по-умолчанию является
access_log. Для установки отстутствия префикса в имени
файла используйте строку нулевой длины.
Resolve Hosts Определяет, преобразовывать или нет IP-адреса удаленного
хоста в соответствующее имя хоста через поиск в DNS.
Установите значение True для преобразования IP-адреса
удаленного хоста в соответствующее имя хоста, используя
поиск в DNS. Установите значение False для отмены поиска
и выдачи удаленного IP-адреса.
Suffix Суффикс, добавляемый к концу каждого имени log-файла.
Если не определено, значением по-умолчанию является
строка нулевой длины, что указывает на отсутствие
суффикса.
Web-
Rendered by www.RenderX.com
Настройка элементов Service Стр. 597 из 626
Web-
Rendered by www.RenderX.com
Стр. 598 из 626 Утилита администрирования Tomcat
Web-
Rendered by www.RenderX.com
Настройка элемента Resources Стр. 599 из 626
3. Введите нужное вам имя в таблицу. Внизу страницы выберите Import Data Sources,
затем выберите из ниспадающего списка JNDI Name. Именем JNDI Name должно быть
имя Global Resource, который вы желаете добавить при помощи утилиты admintool.
4. Для размещения приложения выберите Tools _ Deploy. Когда приложение будет
размещено, в файле server.xml создастся Context и в него будет добавлен Resource
Link.
5. В утилите admintool выберите в левом окне элемент Data Source.
6. Из списка Available Actions выберите Create New Data Source.
7. Установите атрибуты Data Source. Для получения более подробной информации см.
раздел Атрибуты Data Source. Используйте имя JNDI Name, которое вы определили в
утилите deploytool. Добавьте Driver Name, URL, User Name и Password.
8. Выберите Save для сохранения изменений в данной сессии. Выберите Commit Changes
для сохранения изменений при перезагрузке Tomcat.
Если вы выберете Commit Changes, файл <JWSDP_HOME>/conf/server.xml будет обновлен
с записью для Resource и Resource Params в элементе GlobalNamingResources. Resource,
созданный здесь, связан с контекстом через элемент Resource Link.
Дальнейший пример является частью файла server.xml, который отображает Resource и
связанный с ним элемент ResourceParams в GlobalNamingResources, а также ссылку на
Resource внутри контекста.
<GlobalNamingResources>
<Environment description="Absolute Path name of the JWSDP
Installation" name="jwsdp.home"
override="true" type="java.lang.String"
value="/home/your_name/jwsdp-1_0"/>
<Resource auth="Container" description="Users and Groups
Database" name="UserDatabase"
scope="Shareable"
type="org.apache.catalina.UserDatabase"/>
<Resource name="jdbc/ActivityDB" scope="Shareable"
type="javax.sql.DataSource"/>
<ResourceParams name="UserDatabase">
<parameter>
<name>factory</name>
<value>org.apache.catalina.users.MemoryUserDatabaseFactory</value>
</parameter>
<parameter>
<name>pathname</name>
<value>conf/tomcat-users.xml</value>
Web-
Rendered by www.RenderX.com
Стр. 600 из 626 Утилита администрирования Tomcat
</parameter>
</ResourceParams>
<ResourceParams name="jdbc/ActivityDB">
<parameter>
<name>validationQuery</name>
<value></value>
</parameter>
<parameter>
<name>user</name>
<value>your_user_name</value>
</parameter>
<parameter>
<name>maxWait</name>
<value>5000</value>
</parameter>
<parameter>
<name>maxActive</name>
<value>4</value>
</parameter>
<parameter>
<name>password</name>
<value>your_password</value>
</parameter>
<parameter>
<name>url</name>
<value>jdbc:pointbase:server://localhost/ActivityDB</value>
</parameter>
<parameter>
<name>driverClassName</name>
<value>com.pointbase.jdbc.jdbcUniversalDriver</value>
</parameter>
<parameter>
<name>maxIdle</name>
<value>2</value>
</parameter>
</ResourceParams>
</GlobalNamingResources>
<Context
className="org.apache.catalina.core.StandardContext"
cachingAllowed="true"charsetMapperClass="org.apache.
catalina .util.CharsetMapper" cookies="true"
Web-
Rendered by www.RenderX.com
Настройка элемента Resources Стр. 601 из 626
crossContext="false" debug="0"displayName="JSTLActTrack"
docBase="/home/your_name/work/Standard
Engine_ocalhost\manager\JSTLActTrack.war"
mapperClass="org.apache.catalina.core.
StandardContextMapper" path="/JSTLActTrack"
privileged="false"reloadable="false" useNaming="true"
wrapperClass="org.apache.catalina.core.StandardWrapper">
<ResourceLink global="jdbc/ActivityDB" name="ActivityDB"/>
</Context>
Web-
Rendered by www.RenderX.com
Стр. 602 из 626 Утилита администрирования Tomcat
путь к директории, в которую был установлен Java WSDP, который уже определен как
Environment Entry.
Для редактирования Environment Entry
1. В левом окне разверните элемент Resources.
2. Выберите Environment Entries.
3. Выберите в правом окне Environment Entry для редактирования. По-умолчанию,
отобразится запись окружения для абсолютного пути к директории, в которую был
установлен Java WSDP.
4. Отредактируйте значения в правом окне.
5. Выберите Save для сохранения изменений в данной сессии. Выберите Commit Changes
для сохранения изменений при перезагрузке Tomcat.
Для создания нового Environment Entry для Tomcat
1. В левом окне выберите элемент Environment Entries.
2. Из списка Available Actions выберите Create New Env Entry.
3. Установите атрибуты Environment Entries. Для получения более подробной информации
см. раздел Атрибуты элемента Environment Entries.
4. Выберите Save для сохранения изменений в данной сессии. Выберите Commit Changes
для сохранения изменений при перезагрузке Tomcat.
Web-
Rendered by www.RenderX.com
Администрирование ролей, групп и пользователей Стр. 603 из 626
Web-
Rendered by www.RenderX.com
Стр. 604 из 626 Менеджер Web-приложений Tomcat (Tomсat Web Application Manager)
Web-
Rendered by www.RenderX.com
Исполнение команд менеджера с использованием задач Ant Стр. 605 из 626
Так как страницы manager являются защищенными Web-ресурсами, при первом вызове
команды manager появится диалоговое окно для аутентификации. При входе в manager
необходимо воспользоваться теми именем пользователя и паролем, которые были
использованы при установке Java WSDP.
Документ "Manager App HOW-TO", распространяемый вместе с Java WSDP, который можно
найти в файле JWSDP_HOME>/docs/tomcat/manager-howto.html, содержит техническую
информацию о менеджере приложения.
username=ManagerName
Web-
Rendered by www.RenderX.com
Стр. 606 из 626 Сервер реестра Java WSDP
password=ManagerPassword
<property file="${user.home}/build.properties"/>
Web-
Rendered by www.RenderX.com
Использование JAXR API для получения доступа к серверу реестра Стр. 607 из 626
Для получения информации о том, как запустить Tomcat обратитесь к разделу Запуск
Tomcat
Для запуска базы данных Xindice используйте команду:
Команда выполняется в фоновом режиме. Для запуска базы данных может потребоваться
некоторое время.
Для того чтобы узнать, как завершить работу Tomcat обратитесь к разделу Завершение
работы Tomcat.
Для завершения работы базы данных используйте команду:
Web-
Rendered by www.RenderX.com
Стр. 608 из 626 Сервер реестра Java WSDP
#publish.url=https://uddi.microsoft.com/publish
## Registry Server:
query.url=http://localhost:8080/registry-
server/RegistryServerServlet
publish.url=http://localhost:8080/registry-
server/RegistryServerServlet
Web-
Rendered by www.RenderX.com
Использование клиентского сценария командной строки с сервером Стр. 609 из 626
реестра
registry-server-test run-cli-request
-Drequest=xml\GetAuthToken.xml
для UNIX:
registry-server-test.sh run-cli-request
-Drequest=xml/GetAuthToken.xml
При запуске сценарий возвратит тег <authToken>, который содержит тег <authInfo>. Вы
будете использовать значение этого тега в следующем шаге.
Web-
Rendered by www.RenderX.com
Стр. 610 из 626 Сервер реестра Java WSDP
Значение тега действительно в течение одного часа. После окончания действия сценария
его можно перезапустить.
registry-server-test run-cli-request
-Drequest=xml\SaveBusiness.xml
для UNIX:
registry-server-test.sh run-cli-request
-Drequest=xml/SaveBusiness.xml
registry-server-test run-cli-request
-Drequest=xml\FindBusiness.xml
для UNIX:
Web-
Rendered by www.RenderX.com
Использование клиентского сценария командной строки с сервером Стр. 611 из 626
реестра
registry-server-test.sh run-cli-request
-Drequest=xml/FindBusiness.xml
registry-server-test run-cli-request
-Drequest=xml\GetBusinessDetail.xml
для UNIX:
registry-server-test.sh run-cli-request
-Drequest=xml/GetBusinessDetail.xml
registry-server-test run-cli-request
Web-
Rendered by www.RenderX.com
Стр. 612 из 626 Сервер реестра Java WSDP
-Drequest=xml\DeleteBusiness.xml
для UNIX:
registry-server-test.sh run-cli-request
-Drequest=xml/DeleteBusiness.xml
file:line:column:message
registry-server-test run-cli-request
-Drequest=xml\GetRegisteredInfo.xml
для UNIX:
registry-server-test.sh run-cli-request
Web-
Rendered by www.RenderX.com
Использование утилиты Indri для получения доступа к базе данных Стр. 613 из 626
сервера реестра
-Drequest=xml/GetRegisteredInfo.xml
где name_of_file - это имя XML-файла, содержащего UDDI-сообщение. Это хорошая идея
- проверять сообщения перед их отправкой.
Поддиректория xml содержит несколько дополнительных сообщений, которые вы можете
отредактировать и использовать. Кроме того, вы можете создавать свои собственные
сообщения.
Web-
Rendered by www.RenderX.com
Стр. 614 из 626 Сервер реестра Java WSDP
//uddi:businessEntity/uddi:name[contains(text(),"Alter")]
Нажмите Find.
Проверьте область статуса на наличие сообщения вида:
3. Если совпадений не найдено, выберите узел из панели XNodes в нижней левой части
окна Indri. Содержимое узла появится в области Node.
Web-
Rendered by www.RenderX.com
Добавление в реестр новых пользователей Стр. 615 из 626
D:\jwsdp-1_0\samples\registry-server>registry-server-test run-
md5 -Dpassword=mypass
Buildfile: D:\jwsdp-1_0\samples\registry-server\test-build.xml
Web-
Rendered by www.RenderX.com
Стр. 616 из 626 Сервер реестра Java WSDP
run-md5:
[echo] -- Running md5 for auth --
[java]
[java] The Value of the MD5 Hash is: a029d0df84eb5549
6. Введите значение хэш как значение тега <passwd> в файле UserInfo.xml. Теги <token-
Expiration> или <authInfo> оставьте без изменений.
7. Сохраните файл, но не выходите из редактора.
8. Запустите Indri:
registry-server-test run-indri
Web-
Rendered by www.RenderX.com
Запуск броузера Стр. 617 из 626
jaxr-browser.sh
jaxr-browser
Для получения доступа к серверу реестра посредством броузера перед выполнением
каких-либо запросов или других действий с броузером необходимо удостовериться в том,
что Tomcat и база данных Xindice запущены. Дополнительную информацию можно получить
из раздела Установка сервера реестра.
Для того чтобы можно было получить доступ к внешним реестрам, броузеру требуется
знать ваши установки прокси. По-умолчанию броузер использует установки, определенные
во время инсталляции Java WSDP. Они представлены в файле
<JWSDP_HOME>/conf/jwsdp.properties . Если вы хотите переопределить эти установки,
можно отредактировать этот файл или определить информацию о прокси в командной
строке броузера.
Для того чтобы использовать один прокси сервер для доступа HTTP и HTTPS, определите
новый хост прокси и его порт следующим образом. Обычно используется порт 8080.
Следующая команда показывает, как запустить броузер в системе UNIX.
Web-
Rendered by www.RenderX.com
Стр. 618 из 626 Броузер реестра
Web-
Rendered by www.RenderX.com
Управление данными реестра Стр. 619 из 626
Web-
Rendered by www.RenderX.com
Стр. 620 из 626 Броузер реестра
Web-
Rendered by www.RenderX.com
Управление данными реестра Стр. 621 из 626
Web-
Rendered by www.RenderX.com
Стр. 622 из 626 Броузер реестра
http://localhost:8080/registry-server/RegistryServerServlet
Оставьте настройки хоста как localhost , если сервер реестра находится в вашей системе.
В противном случае измените localhost на полное имя хоста системы, где запущен сервер
реестра. При неправильном вводе имени сообщение об ошибке не появится до тех пор,
пока вы не попробуете осуществить запрос или процесс обновления.
Определите http: как для запросов, так и для обновлений.
Web-
Rendered by www.RenderX.com
Стр. 623 из 626
http://localhost:8080/index.html
Web-
Rendered by www.RenderX.com
Стр. 624 из 626 Схемы кодировок Java
25.1.1. US-ASCII
US-ASCII - это 7-ми битная схема кодировки, которая включает в себя англоязычный
алфавит. Она недостаточно велика, чтобы в нее могли войти символы других языков. По
этой причине данная схема не очень полезна для интернационализации.
25.1.2. ISO-8859-1
Набор символов для западноевропейских языков. 8-ми битовая схема кодировки, в которой
каждому кодируемому символу отводится ровно 8-бит (с другой стороны, из оставшегося
набора символов некоторые коды зарезервированы для обозначения начала мульти-
байтного символа).
25.1.3. UTF-8
UTF-8 - это 8-ми битная схема кодировки. Все символы из англоязычного алфавита
кодируются с использованием 8-ми битовых байтов. Символы других языков кодируются
при помощи 2-х, 3-х или даже 4-х байтов. Следовательно, при использовании UTF-8
создаются компактные документы на английском языке, но документы на других языках
будут в полтора раза больше, чем, если бы для них использовалась схема кодировки UTF-
16. Если большинство текста в документе написано на западноевропейском языке, то
схема UTF-8, в общем-то, является хорошим выбором в качестве кодировки, так как она
позволяет расширить доступ к документу при минимальных затратах на кодирование.
25.1.4. UTF-16
UTF-16 - это 16-ти битная схема кодировки. Ее достаточно для охвата всех символов из
всех алфавитов мира. Для большинства символов этой кодировки используется по 16 бит,
однако для символов-иероглифов (например, в китайском языке) зарезервировано по 32
бита. Документы на западноевропейских языках в кодировке UTF-16 будут вдвое больше,
чем в кодировке UTF-8. Но документы на дальневосточных языках в кодировке UTF-16
будут гораздо меньше.
Примечание: UTF-16 зависит от условий организации байт в системе. И хотя в большинстве
систем в 16-битном или 32-битном слове старшие байты следуют за младшими, в некоторых
других системах используется обратный порядок. Обмен документами в кодировке UTF-
16, не подвергшихся дополнительным преобразованиям, между такими системами
недопустим.
Web-
Rendered by www.RenderX.com
Запросы HTTP Стр. 625 из 626
Web-
Rendered by www.RenderX.com
Стр. 626 из 626 Обзор HTTP
Web-
Rendered by www.RenderX.com