[an error occurred while processing this directive] IT • archiv :: Print

IT • archiv


[an error occurred while processing this directive]

[an error occurred while processing this directive]

Servlet 2.3: Новые возможности раскрыты

[an error occurred while processing this directive](none) [an error occurred while processing this directive](none)[an error occurred while processing this directive] ::
[an error occurred while processing this directive](none)
[an error occurred while processing this directive]([an error occurred while processing this directive] Джасон Хантер [an error occurred while processing this directive])

[an error occurred while processing this directive](none)

Полный update последней спецификации Servlet API.

Servlet API
PDF versionPDF версия
Обзор
В октябре 2000, Sun выпустила в свет "Proposed Final Draft" спецификации Servlet API 2.3. Эта статья объясняет различия между Servlet API 2.2 и 2.3, обсуждает причины этих изменений, и показывает, как писать сервлеты (а теперь еще и фильтры (filters)!) используя 2.3. (В оригинальной версии на английском языке 4,000 слов)

20 Октября, 2000, Sun Microsystems опубликовал "Proposed Final Draft" спецификации Servlet API 2.3 (Смотрите ссылку на официальную спецификацию Ресурсы) Хотя спецификация была опубликована Sun, Servlet API 2.3 в действительности разрабатывался многими независимыми разработчиками и компаниями, работающими в экспертной группе JSR-053, согласуясь с Java Community Process (JCP) 2.0. Дэни Ковард (Danny Coward) из Sun Microsystems возглавляет экспертную группу по сервлетам.

Спецификация не полностью закончена. "Proposed Final Draft" — в одном шаге от официального Final Release, и технические детали еще меняются. Однако эти изменения не должны быть значительными. Фактически, компании, разработчики серверов, уже начали реализацию новых возможностей. Это значит, что пришло время начать изучать то, что придет вместе с Servlet API 2.3.

В этой статье, я опишу в деталях все, что изменилось в API 2.3 по сравнению с API 2.2. Я также объясню причины для этих изменений и продемонстрирую, как писать сервлеты, используя новые возможности. Чтобы не терять направленность статьи, я буду предполагать, что вы знакомы с классами и методами предыдущей версии Servlet API. Если нет, вы можете предварительно обратиться к ресурсам , где найдете ссылки на сайты ( и мою новую книгу!), которые помогут вам набрать скорость в их освоении.

Servlet API 2.3 , в действительности, оставляет ядро сервлетов относительно нетронутым, что показывает — сервлеты уже достигли высокого уровня завершенности. Большинство изменений было связано с добавлением новых возможностей вне ядра. В числе этих изменений:

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

Перед тем как я начну свой обзор, позвольте обратить внимание на тот факт, что версия 2.3 была выпущена только как проект спецификации. Большинство возможностей, которые будут затронуты в этой статье, еще не работают на всех серверах. Если вы хотите проверить эти возможности, я рекомендую взять эталонную реализацию сервера, Apache Tomcat 4.0. Это открытый исходный код и вы можете взять сервер бесплатно. Tomcat 4.0 в настоящий момент в beta версии. Его поддержка API 2.3 постоянно улучшается, но все еще не завершена. Прочитайте файл NEW_SPECS.txt, который идет вместе с Tomcat 4.0, чтобы изучить в какой степени он поддерживает новые возможности спецификации. (Для получения большей информации о Tomcat смотрите Ресурсы .)

Сервлеты в J2SE и J2EE

Одна из главных деталей Servlet API 2.3, которую вы должны себе отметить, — сервлеты теперь находятся в зависимости от Java 2 Platform, Standard Edition 1.2 (также известную как J2SE 1.2 или JDK 1.2). Это маленькое, но важное изменение означает, что вы можете теперь использовать возможности J2SE 1.2 в ваших сервлетах и быть уверенными, что сервлеты будут работать во всех сервлет-контейнерах. Раньше, вы могли использовать возможности J2SE 1.2, но сервера могли не поддерживать их.

Servlet API 2.3 будет частью ядра Java 2 Platform, Enterprise Edition 1.3 (J2EE 1.3). Предыдущая версия, Servlet API 2.2, была частью J2EE 1.2. Единственное заметное различие — добавление нескольких несовсем понятных тэгов DTD, относящихся к J2EE, в файл web.xml: <resource-env-ref> для поддержки "администриуемых объектов", так как они требуются Java Messaging System (JMS); <res-ref-sharing-scope> для возможности как совместного, так и эксклюзивного доступа к ресурсам и, <run-as> для определения системой безопасности подлинности клиента, обращающегося к EJB. Большинство разработчиков сервлетов не нуждаются в использовании этих тэгов J2EE. Вы можете найти их полное описание в спецификации J2EE 1.3.

Фильтры

Наиболее значительная часть изменений API 2.3 — фильтры (filters) — объекты, которые могут преобразовывать запрос (request) или изменять ответ (response). Фильтры — не сервлеты. В действительности, они не создают ответ (response). Они — препроцессоры запроса, перед тем как он достигнет сервлет, и/или постпроцессоры ответа, отправляемого сервлетом. В известном смысле, фильтры более совершенная версия старой концепции сервлетов "servlet chaining" (связывание сервлетов). Фильтр может:

Вы можете сконфигурировать фильтр так, чтобы он действовал на один сервлет или группу сервлетов. Этот сервлет или группа могут не фильтроваться или фильтроваться несколькими фильтрами. Практические идеи использования фильтров: фильтры аутентификации, журналирующие и аудирующие фильтры, фильтры конверторы изображений, фильтры сжатия данных, фильтры кодировщики, фильтры анализаторы текста, фильтры приводящие в действия события доступа к ресурсам, XSLT фильтры, которые преобразуют содержание XML, или MIME-type связывающие фильтры (точно как связывание сервлетов).

Фильтр реализует javax.servlet.Filter и определяет его три метода:

Для подготовки фильтра к работе, сервер единожды вызывает setFilterConfig(), затем вызывает doFilter() любое количество раз, для различных запросов. Интерфейс FilterConfig имеет методы для получения имени фильтра, его параметров инициализации, и активного контекста сервлета. сервер передает null в setFilterConfig() , для указания, что фильтр отключается.

Каждый фильтр принимает в свой метод doFilter() текущий запрос(request) и ответ (response), также как и FilterChain, содержащий фильтры, которые должны быть выполнены. В методе doFilter(), фильтр может делать все что угодно с запросом(request) и ответом (response). (Он может обрабытывать данные сервлетов, вызывая их методы, или прятать объекты, изменяя их поведение, что будет обсуждаться далее). Для предачи контроля в следующий фильтр, фильтр вызывает chain.doFilter(). После завершения этого вызова фильтр может в конце своего собственного метода doFilter(), выполнить дополнительную работу над ответом (response). Например, он может занести в журнал информацию об ответе (response). Если в фильтре надо остановить выполнение запроса (request) и получить полный контроль над ответом (response), он может умеренно не вызывать следующий фильтр.

Фильтр может скрывать объекты запроса (request) и/или ответа (response) для обеспечения стандартного поведения приложения, изменяя истинную реализацию вызова метода, чтобы влиять на управляющие действия более поздних вызовов. Для этой цели API 2.3 содержит новые классы HttpServletRequestWrapper и HttpServletResponseWrapper. Они обеспечивают реализацию по умолчанию всех методов запроса (request) и ответа (response), и делегируют вызовы подлинному запросу(request) или ответу (response) по- умолчанию. Это значит, что изменение поведения одного метода требует только расширения wrapper и повторной реализации одного метода. Wrapper-ы дают фильтрам возможность обширного контроля над запросами и процессом генерации ответа. Ниже показан исходный текст простого журналирующего фильтра, который записывает продолжительность всех запросов:

public class LogFilter implements Filter {
   FilterConfig config;

   public void setFilterConfig(FilterConfig config) {
     this.config = config;
   }

   public FilterConfig getFilterConfig() {
     return config;
   }

   public void doFilter(ServletRequest req,
                         ServletResponse res,
                         FilterChain chain) {
      ServletContext context =
 		getFilterConfig().getServletContext();
      long bef = System.currentTimeMillis();
       // никакие параметры связывания здесь не нужны
      chain.doFilter(req, res);
      long aft = System.currentTimeMillis();
      context.log("Request to " +
          req.getRequestURI() + ": "
          + (aft-bef));
   }
 }

Когда сервер вызывает setFilterConfig(), фильтр сохраняет ссылку на config в своей переменной , которая позже используется в методе doFilter() для получения ServletContext. Логика doFilter() проста — занести в журнал время, занимаемое запросом. Для использования этого фильтра, вы должны объявить в web.xml дескриптор развертывания, используя тег <filter>, как показано ниже

<filter>
   <filter-name>
     log
   </filter-name>
    <filter-class>
     LogFilter
   </filter-class>
 </filter>

Теперь сервер узнает, что фильтр, называемый log, реализован в классе LogFilter. Вы можете использовать зарегистрированный фильтр для определенных шаблонов URL или имен сервлетов, используя тэг <filter-mapping>:

<filter-mapping>
   <filter-name>log</filter-name>
   <url-pattern>/*</url-pattern>
 </filter-mapping>

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

Request to /index.jsp: 10

События времени жизни

Второе из наиболее значительных изменений Servlet API 2.3 — добавление событий времени жизни приложения, которые позволяют объектам "слушателям"(listeners) знать, когда контексты сервлетов и сессии инициализированы или уничтожены, а также как когда атрибуты добавлены или удалены из контекста или сессии.

События времени жизни сервлета работают подобно событиям в Swing. Любой слушатель, заинтересованный в наблюдении за временем жизни ServletContext может реализовывать интерфейс ServletContextListener. Интерфейс имеет два метода:

Класс ServletContextEvent, передаваемый этим методам, имеет только метод getServletContext(), возвращающий инициализируемый или удаляемый контекст.

Слушатель, отслеживающий состояния времени жизни ServletContext, реализует интерфейс ServletContextAttributesListener, в который входит три метода:

Класс ServletContextAttributeEvent расширяет ServletContextEvent, и добавляет методы getName() и getValue() так, что слушатель может узнать об изменяемых атрибутах. Это полезно, когда нужно синхронизировать состояние приложения (атрибуты контекста) с другими приложениями, такими как, например, база данных.

Модель слушателя сессий аналогична модели слушателя контекста. В модели сессии есть интерфейс HttpSessionListener с двумя методами:

Методы принимают событие HttpSessionEvent с помощью метода getSession(), чтобы узнать создается или уничтожается сессия. Вы можете использовать все эти методы, когда реализуете интерфейс администратора, отслеживающий всех активных пользователей в Web приложении.

Модель сессии также имеет интерфейс HttpSessionAttributesListener с тремя методами. Эти методы сообщают слушателю, когда атрибуты меняются, и могут быть использованы, например, приложением, которое синхронизирует параметры сохраняемых в базе данных сессий:

Как и следовало ожидать, класс HttpSessionBindingEvent расширяет HttpSessionEvent и добавляет методы getName() и getValue(). Единственное что здесь может показаться странным, это то, что класс называется HttpSessionBindingEvent, а не HttpSessionAttributeEvent. Просто по причине совместимости со старым API был использован уже действующий класс HttpSessionBindingEvent. Возможно, это будет изменено перед выпуском Final Release.

Одно из практических применений событий времени жизни — совместные соединения с базой данных, управляемые слушателем контекста. Вы объявляете слушателя в web.xml как показано ниже:

 <listener>
   <listener-class>
     com.acme.MyConnectionManager
   </listener-class>
  </listener>

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

public class MyConnectionManager
	implements ServletContextListener {

   public void contextInitialized(ServletContextEvent e) {
     Connection con = // создание соединения
     e.getServletContext().setAttribute("con", con);
   }

   public void contextDestroyed(ServletContextEvent e) {
     Connection con =
 	(Connection) e.getServletContext().
 		getAttribute("con");
     try { con.close(); } catch (SQLException ignored)
 	 { } // закрытие соединения
   }
 }

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

HttpSessionActivationListener, другой, новый интерфейс слушателя в API 2.3, спроектирован для управления сессиями мигрирующими от одного сервера к другому. Слушатель, реализующий HttpSessionActivationListener извещается, когда какая-либо сессия почти начала passivate (завершилась) и когда сессия почти activate (активизировалась) на втором сервере. Эти методы дают приложению возможность передавать не сериализуемые данные между различными JVM, собирать и разделять сериализованные объекты в какую-либо объектную модель до или после миграции. Интерфейс имеет два метода:

Вы регистрируете этот вызов также как и всегда. Однако, в отличие от обычных, вызовы passivate и activate будут, скорее всего, происходить на двух разных серверах!

Выбор кодировки символов

API 2.3 обеспечивает столь необходимую поддержку по управлению обработкой форм на иностранных языках. Вводится новый метод, request.setCharacterEncoding(String encoding) который позволяет вам сообщить серверу кодировку символов запроса. Кодировка символов (character encoding), также известная как charset, метод отображения байтов в символы. Сервер может использовать специфический charset, чтобы корректно преобразовывать параметры и данные POST. По умолчанию сервер преобразует параметры, используя обычно Latin-1 (ISO 8859-1) charset. К сожалению, он работает только с Западноевропейскими языками. Когда браузер использует другой charset, предполагается посылать информацию о кодировке в заголовок Content-Type запроса. Не каждый браузер делает это. Метод позволяет сообщать серверу, какой именно charset используется (обычно это charset страницы, содержащей форму). Обо всем остальном заботится сервер . Например, сервлет, принимающий параметры на японском языке от формы кодированной Shift_JIS, может прочитать параметры таким образом:

  // установить charset — Shift_JIS
   req.setCharacterEncoding("Shift_JIS");

   //Читать параметр, используя charset
   String name = req.getParameter("name");

Не забудьте установить кодировку перед вызовом getParameter() или getReader(). Вызов setCharacterEncoding() может вызвать исключение java.io.UnsupportedEncodingException если кодировка не поддерживается. Эта функциональность также доступна для пользователей API 2.2 и более ранних версий, в классе com.oreilly.servlet.ParameterParser. (Смотрите Ресурсы .)

JAR зависимости

Часто, WAR файл (архивный файл Web приложения, добавленный в API 2.2) требует других дополнительных JAR библиотек для своего существования на сервере и нормальной работы. Например, Web приложению, использующему класс ParameterParser, необходим cos.jar в classpath. Web приложению, использующему WebMacro необходим webmacro.jar. Перед появлением API 2.3, или эти зависимости надо было документировать (если кто вообще читает документацию!) или включать все необходимые jar файлы в каталог WEB-INF/lib, без необходимости раздувая Web приложение.

Servlet API 2.3 позволит вам описать JAR зависимости внутри WAR, используя файл META-INF/MANIFEST.MF. Это стандартный путь объявления зависимостей jar файлов, но с появлением API 2.3, WAR должны официально поддерживать тот же механизм. Если зависимость не может быть удовлетворена, сервер может вежливо отклонить Web приложение еще на этапе развертывания вместо того, чтобы вызывать непонятные ошибки на этапе выполнения. Механизм дает высокую степень модульности. Например, вы можете описать зависимость на конкретную версию необязательного пакета, и сервер должен правильно найти его с помощью поискового алгоритма. (Смотрите ресурсы с ссылкой на документацию, объясняющую в деталях, как работает manifest versioning model)

Загрузчики классов (Class loaders)

Небольшое изменение с серьезными последствиями: сервлет-контейнер (a.k.a. сервер) API 2.3, гарантирует, что классам Web приложения не позволено видеть реализации серверных классов. Другими словами, загрузчики классов должны храниться отдельно.

С виду это не серьезное изменение, но оно сокращает возможность столкновений между классами Web приложений и классами сервера. Это стало серьезной проблемой в связи с конфликтами XML парсеров. Каждому серверу нужен XML парсер для анализа web.xml файлов, и многие Web приложения в наши дни также используют XML парсер для управления чтением, манипуляцией, записью XML данных. Если парсеры поддерживаются различных версий DOM или SAX, это становится причиной неисправимого конфликта. Разделение сфер действия классов решает эту проблему.

Новые атрибуты ошибок.

Предыдущая версия API , Servlet API 2.2, добавила в запросы несколько свойств, которые используются сервлетам и JSP, через тэг <error-page>. Если вы не помните, <error-page> позволяют выводить специфические страницы на определенные коды ошибок и исключений:

<web-app>
     <!-- ..... -->
     <error-page>
         <error-code>
             404
         </error-code>
         <location>
             /404.html
         </location>
     </error-page>
     <error-page>
         <exception-type>
             javax.servlet.ServletException
         </exception-type>
         <location>
             /servlet/ErrorDisplay
         </location>
     </error-page>
     <!-- ..... -->
 </web-app>

Сервлет в <location> получает следующие три свойства из <error-page> :

Таким образом, сервлет может генерировать ошибочную страницу под конкретную ошибку, как показано ниже:

import java.io.*;
 import javax.servlet.*;
 import javax.servlet.http.*;

 public class ErrorDisplay extends HttpServlet {

   public void doGet(HttpServletRequest req,
 	httpServletResponse res)
                 throws ServletException, IOException {
     res.setContentType("text/html");
     PrintWriter out = res.getWriter();

     String code = null, message = null, type = null;
     Object codeObj, messageObj, typeObj;

     // Получить три возможных атрибута ошибок,
     // некоторые из которых могут быть null
     codeObj = req.getAttribute(
 	"javax.servlet.error.status_code");
     messageObj = req.getAttribute(
 	"javax.servlet.error.message");
     typeObj = req.getAttribute(
 	"javax.servlet.error.exception_type");

     // Преобразовать атрибуты в строковые значения
     // Мы делаем это таким образом,
     // потому что некоторые старые сервера возвращают строковые
     // тогда как новые сервера возвращают Integer, String, и Class типы.
     // Это работает на всех.
     if (codeObj != null) code = codeObj.toString();
     if (messageObj != null) message = messageObj.toString();
     if (typeObj != null) type = typeObj.toString();

     // Причина ошибки код состояния или тип исключения
     String reason = (code != null ? code : type);

     out.println("<HTML>");
     out.println("<HEAD><TITLE>" +
 	reason + ": " + message +
 	"</TITLE></HEAD>");
     out.println("<BODY>");
     out.println("<H1>" +
 	reason + "</H1>");
     out.println("<H2>" +
 	 message + "</H2>");
     out.println("<HR>");
     out.println("<I>Error accessing " +
 	req.getRequestURI() + "</I>");
     out.println("</BODY></HTML>");
   }
 }

А может ошибочная страница содержать стек трассировки исключений или URI сервлета, который в действительности был причиной проблемы (это не всегда запрашиваемый URI)? В API 2.2 — нет. В API 2.3 эта информация доступна с помощью двух новых свойств:

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

import java.io.*;
 import javax.servlet.*;
 import javax.servlet.http.*;

 public class ErrorDisplay extends HttpServlet {

   public void doGet(
 	HttpServletRequest req, HttpServletResponse res)
        throws ServletException, IOException {
     res.setContentType("text/html");
     PrintWriter out = res.getWriter();

     String code = null, message = null, type = null, uri = null;
     Object codeObj, messageObj, typeObj;
     Throwable throwable;

     // Получение трех возможных атрибутов ошибок,
     // некоторые из которых могут быть null
     codeObj = req.getAttribute(
 	"javax.servlet.error.status_code");
     messageObj = req.getAttribute(
 	"javax.servlet.error.message");
     typeObj = req.getAttribute(
 	"javax.servlet.error.exception_type");
     throwable = (Throwable) req.getAttribute(
 	"javax.servlet.error.exception");
     uri = (String) req.getAttribute(
 	"javax.servlet.error.request_uri");

     if (uri == null) {
       uri = req.getRequestURI(); // в случае если URI нет
     }

     // Преобразовывает атрибуты в строковые значений
     if (codeObj != null) code = codeObj.toString();
     if (messageObj != null) message = messageObj.toString();
     if (typeObj != null) type = typeObj.toString();

     // причина ошибки или код возврата или тип исключения
     String reason = (code != null ? code : type);

     out.println("<HTML>");
     out.println("<HEAD><TITLE>" +
 	reason + ": " + message +
 	"</TITLE></HEAD>");
     out.println("<BODY>");
     out.println("<H1>" +
 	reason + "</H1>");
     out.println("<H2>" +
 	message + "</H2>");
     out.println("<PRE>");
     if (throwable != null) {
       throwable.printStackTrace(out);
     }
     out.println("</PRE>");
     out.println("<HR>");
     out.println("<I>Error accessing " +
 	uri + "</I>");
     out.println("</BODY></HTML>");
   }
 }

Новые возможности системы безопасности

Servlet API 2.3 добавляет два новых свойства запросов(request), для принятия решения по управлению безопасными HTTPS соединениями. Новые свойства:

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

public boolean isAbove128(HttpServletRequest req) {
   Integer size = (Integer) req.getAttribute(
 	"javax.servlet.request.key_size");
   if (size == null || size.intValue() < 128) {
     return false;
   }
   else {
     return true;
   }
 }
Замечание
Имена атрибутов в Proposed Final Draft используют тире вместо подчеркивания, однако, до Final Release, они будут изменяться, как показано здесь, чтобы лучше согласовываться с существующими именами.

Мелкие доработки

В API 2.3 сделано множество небольших доработок. Например, метод getAuthType() , возвращающий тип аутентификации, использовавшийся для идентификации клиента был определен для возврата одного из четырех новых static final String констант в класс HttpServletRequest: BASIC_AUTH, DIGEST_AUTH, CLIENT_CERT_AUTH, и FORM_AUTH. Это позволяет упростить код таким образом:

if (req.getAuthType() == req.BASIC_AUTH) {
   // выполнение основной аутентификации
}

Конечно, эти четыре константы все еще имеют традиционные строковые значения, так что последующий код из API 2.2 тоже работает, правда не так быстро и элегантно. Так с помощью equals() происходит проверка getAuthType() на null, чтобы избежать NullPointerException:

if ("BASIC".equals(req.getAuthType())) {
   // выполнение основной аутентификации
 }

Другое изменение в API 2.3 — объявление класса HttpUtils устаревшим.HttpUtils, также известный, как "класс, который никогда не должен объявляться public", всегда выделялся как набор разрозненных статических методов, полезных, но расположенных не на своем месте. Класс имел методы для реконструкции оригинального URL из запроса (request) объекта и преобразовывал данные параметров в hashtable. В API 2.3 эта функциональность перешла в объект запроса(request), которому она больше подходит. Сам же HttpUtils объявляется устаревшим. Новые методы запроса(request):

API 2.3 добавляет два новых метода к ServletContext позволяющие получить имя контекста и список ресурсов, которые он содержит:

В объект ответа (response) добавлены новые методы контроля за буфером ответов.В API 2.2 есть метод res.reset() для сброса ответа (response) и очистки тела ответа (response), заголовков, и кода состояния. API 2.3 добавляет res.resetBuffer() который очищает только тело ответа(response):

Наконец, после продолжительных дебатов экспертной группы, Servlet API 2.3 раз и навсегда пролил свет на то, что происходит с сервлетом, выполняющимся не в корне контекста, при вызове res.sendRedirect("/ index.html"). Дело в том, что Servlet API 2.2 использует неполный путь, например, "/ index.html" , а сервлет-контейнер переводит его в полный, но не говорит, каким образом. Если сервлет, делает вызов из контекста с путем "/contextpath," как должен переводиться перенаправляемый URI, относительно корня контейнера (http://server:port/ index.html) или относительно корня контекста (http://server:port/contextpath/ index.html)? Для лучшей переносимости, необходимо было определить поведение. В результате долгих споров, эксперты решили транслировать URI относительно корня контейнера. Те же, кто хочет привязаться к контексту, могут использовать метод getContextPath().

Преобразование DTD

Наконец Servlet API 2.3 связывает вместе несколько потерянных концов в отношении DTD в web.xml. Например, обрезаются концевые пробелы текстовых значений в файле web.xml. (В стандартном XML, все пустые пробелы обычно сохранялись.) Это правило говорит, что следующие два варианта записи могут быть обработаны одинаково:

<servlet-name>hello</servlet-name>
<servlet-name>  hello</servlet-name>

В API 2.3 для тэга <auth-constraint> вводится групповой символ "*", который может быть использован в <role-name> как символ, позволяющий все роли. Правило, подобное следующему, позволяет всем пользователем осуществлять вход так быстро, как только их роль была точно идентифицирована:

<auth-constraint>
   <role-name>*</role-name> < !-- позволяет все возможные роли -->
 </auth-constraint>

тэг <security-role> можно использовать, в качестве параметра метода isUserInRole(). анпример, опишем <security-role> в web.xml:

<servlet>
     <servlet-name>
         secret
     </servlet-name>
     <servlet-class>
         SalaryViewer
     </servlet-class>
     <security-role-ref>
         <role-name>
             mgr < !-- имя, используемое сервлетом -->
         </role-name>
< !-- имя используемое в дескрипторе развертывания -->
         <role-link>
             manager
         </role-link>
     </security-role-ref>
 </servlet>

 <!-- ... -->

 <security-role>
     <role-name>
         manager
     </role-name>
 </security-role>

Сервлет secret может вызвать isUserInRole("mgr") или isUserInRole("manager") — результат будет одинаковый. Главным образом, security-role-ref нужен для создания алиаса, но он не обязателен. Вы вероятно так и думали, но по спецификации API 2.2 кажется можно использовать только роль, объявленную в алиасе <security-role-ref>. (Если это не имеет для вас какого-либо смысла, не беспокойтесь об этом, просто помните, что не все всегда работает, так как описано).

Заключение

Как я писал в этой статье, Servlet API 2.3 включает впечатляющий механизм фильтров, расширенную модель периода жизни, новую функциональность в поддержке интернационализации(internationalization), управления ошибками, безопасными соединениями, пользовательскими ролями. Документация на спецификацию была сжата, чтобы убрать повторения, которые могли повлиять на межплатформенное использование. В итоге,добавлены 15 новых классов (большинство для работы с моделью периода жизни, остальные для работы с фильтрами), четыре метода к уже существующим классам, четыре новых константы, и один класс объявлен устаревшим. Краткий список различий между 2.2 на 2.3, смотрите в Списке изменений .

Об авторе

Джасон Хантер (Jason Hunter) главный специалист по технологиям CollabNet, которая разрабатывает инструменты и сервисы для систем с открытым кодом. Он, автор Java Servlet Programming, 2-ая редакция (O'Reilly), издатель Servlets.com, участник Apache Tomcat (он работал над проектом, когда тот еще был внутренним, Sun-овским), член экспертной группы ответственной за Servlet/JSP и JAXP API разработку. Он также член JCP Executive Committee, наблюдающего за Java платформой, как представитель Apache Software Foundation. Совсем недавно он участвовал в совместной работе по созданию открытого исходного кода библиотеки JDOM для обеспечения возможности интеграции Java и XML.

Ресурсы

Новые классы Новые методы Новые константы Устаревшие классы
Filter, FilterChain, FilterConfig, ServletContextAttributeEvent, ServletContextAttributesListener, ServletContextEvent, ServletContextListener, ServletRequestWrapper, ServletResponseWrapper, HttpServletRequestWrapper, HttpServletResponseWrapper, HttpSessionActivationListener, HttpSessionAttributesListener, HttpSessionEvent, HttpSessionListener getResourcePaths(), getServletContextName(), resetBuffer(), HttpSessionBindingEvent.getValue() BASIC_AUTH, DIGEST_AUTH, CLIENT_CERT_AUTH, and FORM_AUTH HttpUtils
Таблица 1. Краткий список изменений Servlet API 2.3

Reprinted with permission from the January 2001 edition of JavaWorld magazine. Copyright © ITworld.com, Inc., an IDG Communications company.
View the original article at: http://www.javaworld.com/javaworld/ jw-01-2001/jw-0126-servletapi.html

[an error occurred while processing this directive]
[an error occurred while processing this directive] Перевод на русский © Дмитрий Зацеляпин, 2001
< Вернуться на caйт :: Copyright © 1999 — 2010, IT • archiv.