Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

Секреты программирования для Internet на Java

.pdf
Скачиваний:
181
Добавлен:
02.05.2014
Размер:
3.59 Mб
Скачать

вернуть TT_EOL; если false, символы EOL будут пропускаться как пробел.

slashStarComments(boolean) Если значение равно true, nextToken распознает комментарии в форме /*...*/ и игнорирует их.

lowerCaseMode(boolean)

Если значение равно true, то прежде, чем поместить слова в

 

переменную sval, переводит заглавные буквы в строчные.

pushBack()

Выталкивает последний токен обратно в поток.

int lineno()

Возвращает текущий номер строки.

String toString()

Возвращает текущий токен в формате строки.

Класс StreamTokenizer очень мощный и гибкий. Но пусть вас не пугает широкий спектр его возможностей. Стандартная конфигурация хорошо работает с большинством потоков InputStream. С помощью StreamTokenizer можно научить апплет клиента времени выполнять разбор входных данных при записи их в переменные. Вспомним, что сервер времени возвращает строку в следующей форме:

Sun Jan 21 19:15:01 1996

Мы можем заставить StreamTokenizer разбить эту информацию на две строки, содержащих день и месяц, и на пять значений двойной точности, содержащих число, часы, минуты, секунды и год. Поскольку в новой программе мы использовали класс Vector, нам нужно добавить в начало программы "import.java.util.*". Вот улучшенный метод start и новый метод readTokens.

Пример 13-5. Разбор данных с сервера времени. public void start() {

Socket TimeSocket; StreamTokenizer st; try {

TimeSocket = new Socket(getCodeBase().getHost(),13,true); st = new StreamTokenizer(TimeSocket.getInputStream());

} catch (Exception e) { error = e; return;

}

Мы хотим проигнорировать колонки в выходных данных сервера времени, поэтому при разборе объявим их пробелами. Чтобы упростить анализ, мы написали метод readTokens, который, беря класс StringTokenizer и вектор из значений типа String и Double, пытается отобрать из потока значения этих типов. Токены должны присутствовать в потоке в том же порядке, в каком они присутствуют в векторе, и разделяться только пробелами. В противном случае произойдет новое исключение. Сейчас мы присвоим начальные значения вектору с тем, чтобы он содержал две строки и пять значений типа Double:

st.whitespaceChars(':',':'); Vector tokens = new Vector(7); tokens.addElement(new String()); tokens.addElement(new String()); tokens.addElement(new Double(0)); tokens.addElement(new Double(0)); tokens.addElement(new Double(0)); tokens.addElement(new Double(0)); tokens.addElement(new Double(0)); try {

readTokens(st,tokens); } catch (Exception e) {

error = e; return;

}

output = "The data is "+tokens.elementAt(0)+", ";

output = output + tokens.elementAt(1)+" "+tokens.elementAt(2); output = output + ", "+tokens.elementAt(6);

try {

TimeSocket.close(); } catch (Exception e) {}

Ⱦɚɧɧɚɹ ɜɟɪɫɢɹ ɤɧɢɝɢ ɜɵɩɭɳɟɧɚ ɷɥɟɤɬɪɨɧɧɵɦ ɢɡɞɚɬɟɥɶɫɬɜɨɦ %RRNV VKRS Ɋɚɫɩɪɨɫɬɪɚɧɟɧɢɟ ɩɪɨɞɚɠɚ ɩɟɪɟɡɚɩɢɫɶ ɞɚɧɧɨɣ ɤɧɢɝɢ ɢɥɢ ɟɟ ɱɚɫɬɟɣ ɁȺɉɊȿɓȿɇɕ Ɉ ɜɫɟɯ ɧɚɪɭɲɟɧɢɹɯ ɩɪɨɫɶɛɚ ɫɨɨɛɳɚɬɶ ɩɨ ɚɞɪɟɫɭ piracy@books-shop.com

}

Ниже мы приводим новый метод для чтения токенов. Он проходит вектор элемент за элементом, считывая токены из потока и устанавливая соответствующие элементы вектора. Если тип токена, прочитанного из потока, не соответствует типу элемента Object, определенного в векторе, или если вектор содержит тип Object, который мы не можем распознать, выдается следующее исключение:

private void readTokens(StreamTokenizer st, Vector v) throws Exception { int token;

int i = 0;

Enumeration en = v.elements(); while (en.hasMoreElements()) {

// это тип объекта, который нам нужен

Object o = en.nextElement();

// это следующий токен из потока token = st.nextToken();

// если выходным типом является тип String if (o instanceof String) {

// если токен не является словом if (token!=st.TT_WORD) {

Exception e;

e = new Exception("Unexpected token type: "+token); throw e;

// все в порядке, заполняем вектор

} else { v.setElementAt(st.sval,i);

}

// если выходным типом является тип Double } else if (o instanceof Double) {

// если токен не является числом if (token!=st.TT_NUMBER) {

Exception e;

e = new Exception("Unexpected token type: "+token); throw e;

// все в порядке, заполняем вектор

} else {

Double d = new Double(st.nval); v.setElementAt(d,i);

}

}

// если выходным типом является недопустимый тип else {

Exception e;

String type = o.getClass().getName();

e = new Exception("Cannot parse for "+type); throw e;

}

i++;

}

}

Взаимодействие InterApplet c каналами

Java API реализует связь потоков данных между различными потоками (threads). Это свойство можно использовать для того, чтобы, не создавая жесткой и сложной системы методов, дать возможность потокам общаться. Вы можете создать пару канальных (piped) потоков данных, PipedInputStream и PipedOutputStream. Все, что будет записано в PipedOutputStream, будет получено на соединенном с ним PipedInputStream. Один поток может построить пару канальных потоков данных и отдать один из них другому потоку. Теперь потоки смогут сообщаться в одном направлении через поток данных. Если потребуется связь в двух направлениях, можно создать другую пару каналов и задать потокам противоположные типы.

Этот метод полезен не только для межпотоковой связи в одном апплете, но он также позволяет

www.books-shop.com

апплетам разделять контекст (например, на Web-странице), чтобы общаться друг с другом. Апплет AppleContext дает метод getApplets, перечисляющий те апплеты, которым он предоставляет свои ресурсы, и метод getApplet, который берет имя апплета и возвращает ссылку на именованный апплет, если таковой существует. Имена апплетам задаются в HTML-документе: <APPLET CODE="..." WIDTH=### HEIGHT=### NAME="...">

Сделав ссылку на апплет, с которым вы хотите пообщаться, вы можете создать пару канальных потоков данных и передать один из них этому апплету с помощью какого-нибудь заранее определенного метода. Это можно осуществить многими способами. Для простоты мы решили создать подкласс класса Applet, ListenApplet (слушающий апплет), действующий в качестве пассивного слушателя. Другой апплет может запросить у него OutputStream, записать туда данные и велеть ему читать данные из потока. ListenApplet берет данные из потока, интерпретирует их как текст и печатает в TextArea. Вот программа для ListenApplet.

Пример 13-6a. Слушающий апплет (Listening Applet). import java.applet.*;

import java.io.*; import java.awt.*; import java.util.*;

public class ListenApplet extends Applet {

//выходное окно private TextArea output;

//содержит InputStream с ключами апплета private Hashtable inpipes;

public void init() {

inpipes = new Hashtable(1); output = new TextArea(10,60); output.setEditable(false);

output.appendText("This Applet listens for master

applets.\n");

add(output);

}

Апплет может использовать этот метод для того, чтобы OutputStream связался с ним каналом. ListenApplet следит за своими OutputStream, храня хеш-таблицу этих потоков с ключами их соответствующих апплетов. Эта хеш-таблица позволяет осуществлять связь между несколькими апплетами. Апплет, который хочет поговорить с данным апплетом, начинает диалог с обращения к методу, вызывающему ListenApplet. Вызывающий метод создает пару канальных потоков и пропускает PipedOutputStream обратно к говорящему апплету:

public PipedOutputStream call(Applet a) throws IOException {

//на случай, если апплет а уже соединен inpipes.remove(a);

PipedInputStream in

in = new PipedInputStream(); PipedOutputStream out

out = new PipedOutputStream();

//соединяем каналы друг с другом in.connect(out);

out.connect(in);

//храним InputStream для дальнейшего использования inpipes.put(a,in);

//возвращаем парный OutputStream

return out;

}

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

public void hangup(Applet a) throws IOException { PipedInputStream in

in = (PipedInputStream)inpipes.get(a); in.close();

inpipes.remove(a);

www.books-shop.com

}

Если другой апплет записал данные в поток, наш апплет считывает данные из потока до тех пор, пока они там есть, конвертирует их в тип String и печатает в поле TextArea. Если вам нужно работать с несколькими апплетами, взаимодействующими синхронно, лучше поместить этот метод в отдельный поток. Сначала мы считываем данные в буфер длиной 8. Достигнув границ массива, мы создаем новый массив с удвоенной по сравнению с предыдущим массивом длиной. Этот способ обращения с неизвестным количеством данных с помощью массивов представляется еще более сложным, чем те, что мы рассматривали раньше. Вместо того чтобы просто копировать данные в несколько массивов, как в нашем предыдущем примере, мы используем один массив, но как только он наполнится, мы удвоим его длину:

public void listen(Applet a) throws IOException { PipedInputStream in = (PipedInputStream)inpipes.get(a); if (in==null) {

return;

}

int count = 0; int arysize = 8;

byte ary[] = new byte[arysize]; byte b;

b = (byte)in.read(); // если поток не полный while (b!=-1) {

// если мы уже наполнили наш массив if (count==arysize) {

arysize = arysize*2;

byte temp[] = new byte[arysize];

//эта последняя система вызывается

//для копирования массива

System.arraycopy(ary,0,temp,0,count); ary = temp;

}

ary[count] = b; count++;

b = (byte)in.read();

}

String buffer = new String(ary,0); output.appendText("Received: "+buffer);

}

}

Слушающий апплет будет сидеть на Web-странице без дела. Необходимо вызвать второй апплет, чтобы с ним поговорить. Ниже приводится программа для разговаривающего апплета. Заметьте, что, поскольку мы используем расширенные свойства апплета ListenApplet, мы должны его импортировать.

Пример 13-6b. Разговаривающий апплет (Talking Applet). import ListenApplet;

import java.awt.*; import java.io.*; import java.applet.*;

public class MasterApplet extends Applet {

//входное пользовательское окно private TextArea output;

//сигнал посылать входные данные private Button send;

public void init() {

output = new TextArea(10,60); output.setEditable(true); send = new Button("Send"); add(send);

add(output);

www.books-shop.com

}

Как только пользователь нажимает на кнопку "Послать", выполняется метод action. Мы находим апплет, с которым хотим поговорить, и посылаем ему содержимое поля TextArea:

public boolean action(Event evt, Object o) { if (evt.target!=send) {

return false;

}

ListenApplet slave

slave = (ListenApplet)getAppletContext().getApplet("listener"); if (slave==null) {

output.appendText("Found no listening applet.\n");

}else try { sendMessage(output.getText(),slave); output.setText("");

}catch (IOException e) {

output.appendText(e.toString()+"\n");

}

return true;

}

В программе, приведенной ниже, мы пытаемся послать строку на выходной (target) апплет. Для начала мы вызываем апплет, чтобы он получил OutputStream. Затем мы конвертируем строку в массив байтов и записываем его в поток, добавив новую строку и символ EOF. Мы просим другой апплет прочесть содержимое потока и затем закрыть связь:

public void sendMessage(String s, ListenApplet a) throws IOException { PipedOutputStream out;

out = a.call(this);

byte b[] = new byte[s.length()]; s.getBytes(0,s.length(),b,0); out.write(b);

byte NL = '\n'; out.write(NL); byte EOF = -1; out.write(EOF); a.listen(this); a.hangup(this); out.close();

}

}

HTML-код для Web-страницы, включающей оба этих апплета, выглядит следующим образом:

<APPLET CODE="ListenApplet.class" WIDTH=500 HEIGHT=250

NAME="Listener"></Applet>

<APPLET CODE="MasterApplet.class" WIDTH=500 HEIGHT=250></APPLET>

Что дальше?

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

Ваш Web-броузер может поддерживать по крайней мере протокол HTTP (HyperText Transfer Protocol, "протокол передачи гипертекста"). Наиболее популярные броузеры поддерживают как HTTP, так и FTP (File Transfer Protocol, "протокол передачи файлов") для передачи объектов, а некоторые поддерживают протокол NNTP (Network News Transfer Protocol, "протокол передачи сетевых новостей") для просмотра групп телеконференций. Все эти протоколы можно

www.books-shop.com

закодировать в URL. Java API работает по умолчанию с некоторыми протоколами и, кроме того, содержит механизм для разработки собственных драйверов URL, которые могут понимать другие протоколы. Кроме того, URL-классы Java позволяют легко искать в сетях не только простые типы данных, но и объекты Java. Мы уже видели один такой пример под названием getImage(URL). В следующей главе мы покажем, как проектировать собственный поиск объектов.

Глава 14

Связь по сети с помощью URL

Использование класса URL Получение содержимого

Соединение с помощью класса URLConnection HTTP и класс URLConnection

Типы MIME и класс ContentHandler Класс ContentHandlerFactory

Сделайте это сами с помощью потоков Настройка класса URLConnection

Работа с другими протоколами Чем хороши URL

URL (Uniform Resource Locator, "унифицированная ссылка на ресурс") используется для того, чтобы находить ресурсы в сети Интернет. Разработчики Web-страниц могут делать на своих документах ссылки (links), указывающие на другие Web-страницы или ресурсы Интернет. URL позволяют кодировать местоположение ресурсов сети. Java API включает полный набор классов, помогающих программистам пользоваться URL для доступа к сетевым ресурсам.

Если мы будем использовать URL, а не непосредственно сокеты, мы сможем расширить возможности многократного использования нашей программы. Как будет видно дальше, URLклассы Java позволяют разделить процессы соединения с сетевым ресурсом и интерпретации его данных. Преимущественно URL используются для поиска данных, хотя некоторые из них, например Telnet URL, применяются для того, чтобы получить интерактивный доступ к ресурсам сети. В табл. 14-1 перечислены URL, которые удовлетворяют спецификациям самых общих протоколов. Классы URL, содержащиеся в Java API, предназначены для использования URL при поиске данных, хотя с интерактивными URL работать также легко.

Таблица 14-1. Наиболее распространенные URL

Протокол

URL

HTTP (HyperText Transfer Protocol)

http://www.vmedia.com/

FTP (File Transfer Protocol)

ftp://ftp.vmedia.com/pub

SMTP (Simple Mail Transfer Protocol) mailto:user@host

www.books-shop.com

News (Usenet)

news://sunsite.unc.edu/

WAIS (Wide Area Index and Search) wais://sunsite.unc.edu/linux-faq

Telnet

telnet://www.vmedia.com/

СОВЕТ Официальной спецификацией на формат и структуру URL является RFC 1738, доступная на сервере http://www.cis.ohio-state.edu/htbin/rfc/rfc1738.

Netscape Navigator 2.0 наложил несколько весьма жестких ограничений, касающихся использования URL в апплетах. Эти ограничения, делая ненадежные апплеты более безопасными, в то же время запрещают создание с помощью классов URL драйверов протоколов и типов содержимого, не входящих в обеспечение Netscape. Хотя это отчасти ограничивает использование классов URL, Netscape Navigator 2.0 предлагает поддержку для наиболее широко используемых протоколов. И хотя Netscape Navigator 2.0 не поддерживает непосредственно классы URL для любых типов содержимого, мы покажем, как обойти это ограничение для драйверов в разделе этой главы "Типы MIME и класс ContentHandler". Конечно, для поиска изображений и звуковых файлов вы можете по-прежнему использовать методы класса Applet getImage и getAudioClip.

Использование класса URL

Java содержит класс java.net.URL, позволяющий иметь дело с URL, изначально принадлежавшими Java. Кроме того, в Java есть встроенная поддержка типов протоколов и возможности для программистов создавать собственную поддержку для новых протоколов. В главе 5, "Апплет в работе", мы обсуждали абсолютные и относительные конструктры URL. Все четыре конструктора URL приводятся в табл. 14-2.

 

Таблица 14-2. Конструкторы класса URL

Конструктор

Описание

URL(String,string,int,String) Создает абсолютный URL из типа протокола, имени хоста, номера порта и расположения каталога.

URL(String,String,String)

Создает абсолютный URL из типа протокола, имени хоста, номера

 

порта и расположения каталога. Номер порта для данного типа

 

протокола считается определенным по умолчанию.

URL(String)

Создает абсолютный URL из синтаксически непроанализированной

 

строки.

URL(URL,String)

Создает абсолютный URL из синтаксически непроанализированной

 

строки, содержащей каталог, относительный для данного URL.

Фирма Sun разработала поддержку URL для очень ограниченного числа протоколов - DOC, FILE и HTTP. Ниже в этой главе, в разделе "Работа с другими протоколами" мы обсудим, как создавать свою поддержку для новых протоколов класса URL. Все общие методы класса URL приведены в табл. 14-3.

 

Таблица 14-3. Общие методы класса URL

Метод

Описание

boolean equals(URL)

Сравнивает два URL на эквивалентность.

String getFile()

Возвращает абсолютный путь к ресурсам данного хоста.

String getHost()

Возвращает имя хоста.

int getPort()

Возвращает номер порта.

String getProtocol()

Возвращает тип протокола.

String getRef()

Возвращает ссылку на определенное положение внутри файла.

 

Например, http://WWW.vmedia.com/indexhtml#middle содержит

 

ссылку "middle" на отмеченное место внутри файла index.html.

sameFile(URL)

Сравнивает два URL на эквивалентность, игнорируя все ссылки.

String toExternalForm()

Печатает полностью подготовленный URL.

Object getContent()

Восстанавливает содержимое данного URL.

InputStream openStream() Возвращает InputStream из ресурса.

www.books-shop.com

openConnection()

Возвращает URLConnection для данного URL.

setURLStreamHandleFactory

Задает URLStreamHandleFactory.

(URLStreamHandleFactory)

 

Реализовав класс URL, мы захотим получить доступ к ресурсам, на которые он указывает. Класс URL предлагает для этой цели три основных метода. Наиболее простой заключается в чтении из InputStream, полученного с URL. Это делает метод openStream:

InputStream is; try {

is = myURL.openStream();

//читаем данные из is

}catch (IOException e) {}

Применение URL в этом случае мало отличается от использования сокетов. Основное отличие

состоит в том, что при программировании c помощью URL связь через сокеты автоматически открывается на нужном порту и выполняются все протоколы установки связи (handshaking) и процедур запросов. Например, если вы запрашиваете поток со стандартного HTTP URL, URL открывает сокет на порту 80 на определенной машине и выдает команду GET для определенного положения каталога. InputStream, возвращенный методом openStream, располагается в начале потока байтов данного ресурса. Ниже дается короткий пример чтения непосредственно из

InputStream c URL:

URL myURL; try {

myURL = new URL(getCodeBase(), "/index.html");

} catch (MalformedURLException e) {} try {

InputStream is = myURL.openStream(); int i = is.read();

while (i!=-1) {

// читаем данные из потока

}

} catch (IOEXception e) {}

Здесь мы создаем URL к Web-странице нашего апплета, открываем InputStream, соединенный с этой страницей, и читаем HTML-файл из InputStream.

Получение содержимого

Метод getContent - приятное свойство класса URL, которое в настоящее время мало используется. Этот метод открывает поток к ресурсу в точности так, как это делает метод openStream, но затем пытается определить тип MIME потока и конвертировать поток в объект Java. Зная тип MIME потока данных, URL может передать поток данных методу, созданному для работы именно с этим типом данных. Этот метод должен выдать нам данные, инкапсулированные в соответствующем типе объекта Java. Например, если мы создали URL, указывающий на изображение в формате GIF, метод getContent должен понять, что поток относится к типу "image/gif", и вернуть экземпляр класса Image. Объект Image будет содержать копию GIFкартинки. Точный механизм, используемый методом getContent, будет объяснен ниже в этой главе в разделе "Типы MIME и класс ContentHandler". Ниже приводится пример использования метода getContent. В этом примере мы создаем URL для основного индекса Web-сервера апплета. Мы вызываем метод getContent, чтобы восстановить ресурс в объекте Java, а затем применяем знак операции instanceof для определения того, какой тип объекта возвращен:

URL myURL; try {

myURL = new URL(getCodeBase(), "/index.html");

} catch (MalformedURLException e) {} try {

Object o = myURL.getContent();

www.books-shop.com

}catch (IOEXception e) {} if (o instanceof Image) {

//если о - изображение

}else if (o instanceof String) {

//если о - строка

}else {

//по умолчанию

}

Спецификация MIME

Спецификация типа MIME (Multipurpose Internet Mail Extensions, "много-целевые почтовые расширения Интернет") впервые была предложена в RFC 1341 для упрощения пересылки двоичных данных по e-mail. Вместо того чтобы просто посылать двоичные данные внутри обычного электронного сообщения и надеяться, что получатель их правильно прочтет, MIME позволяет свести воедино все разнообразие информации о двоичных данных, а именно - метод кодирования данных и тот тип программы, которую использует почтовый клиент для просмотра раскодированных данных.

Спецификация MIME доказала свою полезность и в областях, отличных от e-mail, особенно в передаче файлов по HTTP. Когда HTTP-клиент запрашивает файл, при желании он может запросить MIME-информацию о файле и работать с данными в соответствии с типом содержимого файла. Например, если HTTP-клиент получает файл с типом MIME "image/gif", он, возможно, передаст данные подпрограмме или утилите просмотра изображений.

Если вас интересуют ссылки на Web-страницы и RFC, содержащие информацию о MIME,

обращайтесь по адресу http://www.worldtalk.com/web/text/email.html.

Соединение с помощью класса URLConnection

Если вы используете URL, требующий какую-то дополнительную входную информацию, например URL к сценарию CGI, или если вам нужно больше информации о некоем ресурсе, вы можете воспользоваться методом openConnection. Этот метод возвращает объект URLConnection, связанный с URL. Класс URLConnection, содержащийся в Java API, дает абстрактное представление реальной связи между компьютером, на котором находится апплет, и компьютером, содержащим данный ресурс.

Возможно, вам захочется воспользоваться сценарием на CGI в качестве простой внутрисерверной поддержки для своего Java-апплета. Апплеты не могут просто записывать файлы на свой клиент или на свой сервер, но вы легко можете записать безопасный сценарий, и это даст вам доступ на чтение или запись к файлам, находящимся на сервере. Тогда Javaапплеты смогут установить связь по URL с вашим сценарием, что даст вам возможность посылать данные к сетевому ресурсу, чтобы ваш апплет мог передавать свои файловые запросы сценарию через CGI-переменные. Этот сценарий может, в свою очередь, выполнять необходимые операции с файлами и сообщать в выходных данных статус произведенной операции. Эта методика используется в главе 17, "Взаимодействие с CGI: Java-магазин".

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

URLConnection можно создать с помощью метода openConnection класса URL или используя требуемый URL в качестве аргумента. Класс URLConnection дает программистам больше информации и лучшее управление ресурсом, определяемым URL. Согласно описанию Java API, этот класс является абстрактным; подклассы, реализованные для определенных протоколов, включены в JDK. Это относится к протоколам HTTP, FILE и DOC (FILE URL применяется для локальных файлов, а DOC URL использован в броузере Hotjava). Netscape Navigator 2.0 позволяет апплетам при работе с URL использовать только HTTP-протокол.

В классе URLConnection определено много общих методов, дающих легкий доступ к информации о ресурсе, находящемся на данном URL. Эти методы приведены в табл. 14-4. Некоторые из них применимы только при использовании HTTP URL и возвращают null или 0 во всех других случаях.

Таблица 14-4. Информационные методы класса URLConnection

Метод

Описание

String getContentEncoding()

Возвращает закодированные выходные данные ресурса или,,

 

если они неизвестны,, null (например,, base64,, 7bit).

String getContentLength()

Возвращает размер ресурса в байтах.

String getContentType()

Возвращает тип MIME ресурса (например,, image/gif).

www.books-shop.com

String getDate()

Возвращает дату посылки ресурса.

String getExpiration()

Возвращает срок годности ресурса.

String getHeaderField(String)

Возвращает поле заголовка с названием данной строки.

String getHeaderField(int)

Возвращает поле заголовка с индексом данного целого.

String getHeaderFieldKey(int)

Возвращает имя поля заголовка с индексом данного целого.

long

Возвращает поле заголовка с названием данной String,,

getHeaderFieldDate(String,long)

распознанное как дата. Целочисленный аргумент long служит по

 

умолчанию полем заголовка,, если оно не распознано или не

 

найдено.

int getHeaderFieldInt(String,int)

Возвращает поле заголовка с названием данной строки,,

 

распознанное как целое. Целочисленный аргумент служит по

 

умолчанию полем заголовка,, если оно не распознано или не

 

найдено.

long getModifiedSince()

Возвращает поле if modified since.

HTTP и класс URLConnection

Для того чтобы понять, как класс URLConnection работает с простым HTTP URL, рассмотрим кратко внутренние механизмы работы протокола HTTP. Ниже приведена запись типичной сессии HTTP; первая строка является запросом клиента, а все остальное - ответ сервера:

GET /index.html HTTP/1.0 HTTP/1.0 200 Document follows

Date: Sun, 10 Mar 1996 03:52:15 GMT Server: NCSA/1.4

Content-type: text/html

Last-modified: Fri, 08 Mar 1996 20:24:18 Content-lenght: 4611

<html>

. . .

</html>

Если мы создаем URLConnection для страницы index.html из приведенного примера, метод getContentType вернет "text/html", а метод getContentLength вернет "4611". Заметим, что определять эти значения с помощью HTTP исключительно легко - сервер возвращает их в заголовке HTTP. Многие другие протоколы не дают этой информации.

Теперь вернемся к рабочему инструменту методов класса URLConnection, к методу getContent. Именно этот метод реально запускается, когда мы вызываем метод getContent на URL. Для начала метод getContent пытается определить тип содержимого рассматриваемого ресурса, изучая либо заголовок HTTP, либо сам поток, либо расширение имени файла. Решив, какой тип MIME использовать, метод getContent запрашивает класс ContentHandler для данного типа MIME и передается в класс ContentHandler.

Типы MIME и класс ContentHandler

Каждый тип MIME может иметь собственный класс ContentHandler. Этот класс ContentHandler в конечном счете обрабатывает данные ресурса, когда мы вызываем getContent на URL или URLConnection. Класс ContentHandler состоит из одного метода getContent, который использует URLConnection как аргумент и возвращает объект, по возможности относящийся к ресурсу. Например, ресурс с MIME-типом "image/gif" будет скорее всего возвращен как Image или какойто подкласс Image из метода getContent. Класс ContentHandler согласно описаниям Java API является абстрактным; подклассы класса ContentHandler дают реализации для различных типов MIME. Ниже приведен не очень сложный ContentHandler для любых типов "text/*":

import java.net.*; import java.io.*;

public class TextContentHandler extends ContentHandler { public Object getContent(URLConnection urlc) {

try {

InputStream is;

is = urlc.getInputStream();

www.books-shop.com