Соединения содержимого соединений
Интерфейс ContentConnection дополняет интерфейс StreamConnection. Он уточняет понятие потокового соединения. Он определяет соединения, включающие содержимое, вместо представления их как простого потока необработанных байтов или потока, чья структура должна быть отмечена как приоритетная (priori).
Конечно, все потоки содержат некоторого рода «содержимое», основная цель сообщений протокола заключается в транспортировке полезной нагрузки данными. Идея, лежащая в основе интерфейса ContentConnection, заключается в том, что он представляет соединения, которые могут описать свое содержимое некоторым образом, обычно с помощью наличия атрибутов метаинформации, определенных протоколом. Интерфейс ContentConnection предоставляет подробную информацию об извлечении этой информации из потока, так что вам не придется знать синтаксис или семантику протокола реализации.
Интерфейс ContentConnection представляет собой общие характеристики семейства протоколов уровня приложений, которые обычно определяют атрибуты, описывающие транспортируемые ими данные. Более точно, ContentConnection определяет несколько базовых атрибутов, которые являются общими для всех таких соединений содержимого соединений. В таблице 8.3 перечислены три метода, определяемые ContentConnection. Вы можете видеть, как они применяются по отношению к семейству протоколов уровня приложений.
Таблица 8.3. Методы интерфейса ContentConnection
Имя метода ContentConnection | Описание | ||
String getEncoding () | Выдает значение поля, показывающего набор символов шифрования, используемых для представления содержимого сообщения | ||
long getLength() | Выдает длину сообщения |
| |
String getType() | Выдает тип содержимого |
Протоколы, которые могут быть представлены этим интерфейсом, обычно используют некоторого рода пометку атрибута, не зависящую от содержимого, которое они транспортируют. Примером такого протокола является протокол HTTP.
Неудивительно, что интерфейс ContentConnection имеет один подинтерфейс, HttpConnection, который представляет соединения, использующие протокол HTTP. Интерфейс HttpConnection определяется MIDP, а не CLDC. HTTP является протоколом содержимого соединений уровня приложений. Вы, несомненно, понимаете, что три метода интерфейса ContentConnection, перечисленные в таблице 8.3, применимы к HTTP.
Интерфейс HttpConnection расширяет эту абстракцию до более конкретного описания атрибутов соединений протокола HTTP. Он поддерживает передачу запросов и получение откликов, а также возможность извлекать и анализировать поля HTTP как для сообщения запроса, так и для ответа. Он также предусматривает возможность получения информации о самом соединении. В таблице 8.4 перечислены методы интерфейса HttpConnection.
Таблица 8.4. Методы интерфейса HttpConnection
Название метода HttpConnection | Описание |
long getDate ( ) | Выдает значение поля заголовка даты |
long getExpiration () |
Выдает значение поля заголовка Expires |
String getFilef) | Выдает значение поля URL данного соединения |
String getHeaderFieldfint n) | Выдает значение части пронумерованного поля заголовка ключ-значение |
String getHeaderField (String name) | Выдает значение поля заголовка с указанным именем ключа. В качестве аргумента приемлемо любое действительное имя поля HTTP |
long getHeaderFieldDate (String name, long def) | Выдает значение (анализируемое как дата) поля заголовка с указанным ключом |
int getHeaderFieldlnt (String name, int def) | Выдает значение (анализируемое как целое] названного поля заголовка |
String getHeaderFieldKey (int n) | Выдает часть ключа пронумерованного поля заголовка |
String getHostf) | Выдает часть HOST URL данного соединения |
long getLastModif ied() | Выдает значение поля LastModified URL. |
int getPortf) | Выдает значение поля порта URL данного соединения |
String getProtocol () | Выдает имя протокола URL |
String getQueryO | Выдает область запроса URL, часть после первого "?" в URL |
String getReff) | Выдает часть ссылки URL |
String getRequestMethod () | Выдает метод текущего запроса |
String getRequestProperty (String key) | Выдает значение указанного свойства общего запроса |
int getResponseCode() | Выдает код состояния отклика v HTTP |
String getResponseMessage ( ) | Выдает сообщение отклика HTTP, связанное с кодом состояния отклика |
String getURLO | Выдает строковую форму URL |
void setRequestMethod (String method) |
Устанавливает метод для URL; приемлемыми значениями являютсяGET, POST И HEAD |
void setRequestProperty (String key, String value) | Устанавливает значение указанного свойства общего запроса |
В дополнение к этим методам интерфейс HttpConnection также определяет полную совокупность констант, представляющих коды статуса и ошибок HTTP, которые показаны в таблице 8.5. Для получения дополнительной информации о константах кода статуса смотрите HTTP 1.1, спецификацию RFC2616, которую можно найти по адресу http://www.w3c.org или на http://www.ietf.org.
Таблица 8.5. Определения констант интерфейса HttpConnection
Константа HttpConnection | Описание |
static String GET | Представляет метод запроса GET |
static String HEAD | Представляет метод запроса HEAD |
static int HTTP_ACCEPTED | HTTP статус 202 |
static int HTTP_BAD_GATEWAY | HTTP статус 502 |
static int HTTP_BAD_METHOD | HTTP статус 405 |
static int HTTP_BAD_REQUEST | HTTP статус 400 |
static int HTTP_CLIENT_TIMEOUT | HTTP статус 408 |
static int HTTP_CONFLICT | HTTP статус 409 |
static int HTTP_CREATED | HTTP статус 201 |
static int HTTP_ENTITY_TOO_LARGE | HTTP статус 413 |
static int HTTP_EXPECT_FAILED | HTTP статус 41 7 |
static int HTTP_FORBIDDEN | HTTP статус 403 |
static int HTTP_GATEWAY_TIMEOUT | HTTP статус 504 |
static int HTTP_GONE | HTTP статус 410 |
static int HTTP_INTERNAL_ERROR | HTTP статус 500 |
static int HTTP_LENGTH_REQUIRED | HTTP статус 41 1 |
static int HTTP_MOVED_PERM | HTTP статус 301 |
static int HTTP_MOVED_TEMP | HTTP статус 302 |
static int HTTP_MULT_CHOICE | HTTP статус 300 |
static int HTTP_NO_CONTENT | HTTP статус 204 |
static int HTTP_NOT_ACCEPTABLE | HTTP статус 406 |
static int HTTP_NOT_AUTHORITATIVE | HTTP статус 203 |
static int HTTP_NOT_FOUND | HTTP статус 404 |
static int HTTP_NOT_IMPLEMENTED | HTTP статус 501 |
static int HTTP_NOT_MODIFIED | HTTP статус 304 |
static int HTTP_OK | HTTP статус 200 |
static int HTTP_PARTIAL | HTTP статус 20В |
static int HTTP_PAYMENT_REQUIRED | HTTP статус 402 |
static int HTTP_PRECON_FAILED | HTTP статус 412 |
static int HTTP_PROXY_AUTH | HTTP статус 407 |
static int HTTP_REQ_TOO_LONG | HTTP статус 414 |
static int HTTP_RESET | HTTP статус 205 |
static int HTTP_SEE_OTHER | HTTP статус 303 |
static int HTTP_TEMP_REDIRECT | HTTP статус 307 |
static int HTTP_UNAUTHORIZED | HTTP статус 401 |
static int HTTP_UNAVAILABLE | HTTP статус 503 |
static int HTTP_UNSUPPORTED_RANGE | HTTP статус 416 |
static int HTTP_UNSUPPORTED_TYPE | HTTP статус 41 5 |
static int HTTP_USE_PROXY | HTTP статус 305 |
static int HTTP_VERSION | HTTP статус 505 |
static String_HTTP_POST | Представляет метод запроса POST |
Вы можете видеть, что интерфейс HttpConnection предоставляет наибольший набор функциональных возможностей из всех интерфейсов. HTTP является протоколом уровня приложений, наиболее часто поддерживаемым реализациями MIDP.
В листингах с 8.1 по 8.4 показан исходный код для простой программы, которая демонстрирует, как пользователь мобильного устройства может запрашивать ресурс HTTP с удаленного сервера. Вы можете найти, что эта программа не работает при выполнении за пределами вашего корпоративного брандмауэра, в зависимости от конфигураций сети вашей компании, брандмауэра и прокси-сервера. Вы можете быть ограничены до посещения URI ресурсов, расположенных в пределах вашей корпоративной сети.
Протокол HTTP определяет семантику, связанную с тем, что клиентам необходимо запрашивать ресурсы через прокси-сервер. Браузер может изменять URI пользователя, основываясь на настройках его прокси, и посылать измененный запрос на прокси-сервер, который перенаправляет его на исходный сервер. Программа не делает таких изменений URI, и поэтому она не может пересылать URI, как ожидается вашим прокси-сервером. Если вы не знаете, как браузер изменяет URI, у вас могут возникнуть сложности при доступе к URI, являющимся внешним по отношению к вашей корпоративной сети. Результат выразится в том, что программа, показанная в листинге 8.1, сбросит lOException.
Программа, показанная в листинге 8.1, отображает только метаинформацию о запрошенных ресурсах и не отображает сам ресурс. Она лишь запрашивает информацию заголовка для каждого ресурса, используя метод HEAD HTTP. Написание программы, которая отображала бы произвольное содержимое, было бы равноценно написанию целого браузера, что, очевидно, лежит за пределами темы данной книги. К счастью, некоторые компании предлагают HTTP-браузеры, которые работают на устройствах MIDP, так что вам не придется проделывать эту огромную работу.
Листинг 8.1. Программа ConnectionDemo определяет MID-лет, который отображает мета-информацию протокола HTTP, а именно значения полей заголовка HTTP. Программа использует команду HEAD для получения лишь мета информации, а не всей страницы
import javax.microedition.midlet.MI Diet;
import javax.microedition.lcdui.Display;
Этот класс определяет MID- лет для демонстрационной программы, которая
запрашивает у пользователя URI, затем создает соединение HTTP с исходным
сервером и извлекает ресурс. Программа использует
объект Form, для того чтобы дать пользователю возможность ввести URI.
*/
public class ConnectionDemo extends MID-лет
}
private static ConnectionDemo instance;
private URIEntry urlForm; public ConnectionDemo()
super(); instance = this; }
/**
Возвращает один экземпляр класса.
Вызов этого метода до создания объекта возвращает нулевой указатель.
@возвращаем экземпляр данного класса,
public static ConnectionDemo getlnstance ()
return instance;
}
public void startApp()
Display display;
URIEntry urlForm = URIEntry.getlnstance();
display = Display.getDisplay(this); display.setCurrentlurlForm);
}
public void pauseApp()
}
}
void quit ()
destroyApp(true); notifyDestroyedf) ;
}
public void destroyApp(boolean destroy)
{
instance = null;
/**
Устанавливает данный объект в качестве текущего отображаемого
объекта MID- лета .
*/
public void display()
Display.getDisplay(this).setCurrent(urlForm);
}
}
Листинг 8.2. Класс URIEntry описывает форму, которая приглашает пользователя ввести URI
import: javax.micrcedition.midlet.MIDlet;
import javax.microedition.Icdui.Command;
import javax.microedition.Icdui.CommandListener;
import javax.raicroedition.Icdui.Display;
import javax.microedition.Icdui.Displayable;
import javax.microedition.Icdui.Form;
import javax.microedition.Icdui.TextField;
/**
Этот класс задает Form, приглашающую пользователя ввести URI,
с которым должно быть установлено соединение HTTP.
Пользователь вводит URI и нажимает командную кнопку «Go».
Экземпляр данного класса затем создает экземпляр класса ResourceDisplay,
который выполняет обязанности извлечения ресурса HTTP и его отображения.
*/
public class URIEntry extends Form implements CommandListener
}
private static Command go =
new Command("Go", Command.SCREEN, 1);
private static Command exit =
new CommandCExit", Command. EXIT, 1) ;
private static URIEntry instance;
// URI, введенный пользователем, private TextField uri;
// Нить, контролирующая выполнение объекта
// ResourceDisplay. private Thread thread;
/**
Конструктор.
@param title заголовок Form.
*/
private URIEntry(String title)
}
super(title); instance = this;
uri = new TextField. ("Connect to:",
null, 70,
TextField.URL); uri.setStringf'http://") ; append (uri) ;
addCommand(go); addCommand(exit); setCommandListener(this);
}
/**
Выдает один экземпляр данного класса.
^возвращение экземпляра данного класса.
*/
public static URIEntry getlnstance ()
}
if (instance == null)
{
instance = new URIEntry("Enter URL");
}
return instance;
}
/**
Устанавливает этот объект в качестве текущего отображаемого
объекта MID-лета.
*/
public void display()
MIDlet га = ConnectionDemo.getInstance();
Display.getDisplay(m).setCurrent(this);
}
public void commandAction(Command c, Displayable d)
}
if (c == go)
}
// Этот экран отображает метаинформацию ресурса,
// указанного с помощью URI.
ResourceDisplay view =
new ResourceDisplay(uri.getString());
MIDlet m = ConnectionDemo.getInstar.ee ();
Display.getDisplay(m).setCurrent(view);
thread = new Thread(view); thread.start();
}
else if (c == e\it)
}
ConnectionDemo.getlnstance().quit();
}
}
}
Листинг 8.3. Класс ResourceDisplay определяет форму, которая отображает ресурс. Он использует объект helper для получения этого ресурса
import javdx.microedition.lcdui.Command;
import javax.microedition.Icdui.CommandListener;
import javax.microedition.Icdui.Form;
import javax.microedition.Icdui.Displayable;
/**
Данный класс задает Form, которая отображает метаинформацию,
описывающую HTTP-ресурс. Она контролируется отдельной нитью,
поэтому она реализует Runnable.
Этот объект Form использует объект helper для коммуникации с HTTP-ресурсом
через Connection. Он затем забирает данные соединения
из объекта helper для отображения на экране для пользователя.
public class ResourceDisplay extends Form
implements CommandListener, Runnable
{
private static Command back =
new Command("Back", Command.BACK, 1);
private static Displayable instance;
// Объект helper создает соединение с ресурсом на исходном
// сервере и извлекает метаинформацию ресурса.
// private HttpResource resource;
Конструктор.
Sparam uri URI ресурса для извлечения по запросу HTTP протокола.
*/
public ResourceDisplay(String uri)
{
super("Http Info");
instance = this;
resource = new HttpResource(uri);
addCommand(back);
setCommandListener(this);
}
/**
Запускает выполнение данного объекта:
запускает объект helper HttpResource.
@смотри . rtpResource
*/
public void run()
{
resource.run();
append(resource.getResourceMetalnfo());
}
/**
Возвращает один экземпляр данного класса.
Вызов этого метода перед созданием объекта возвращает нулевой указатель.
@возвращаем экземпляр данного класса.
*/
public static Displayable getlnstance ()
{
return instance;
{
public void commandAction(Command c, Displayable d)
{
if (c == back)
{
URI Entry, get Instanced .display();
}
}
}
Листинг 8.4. Класс HttpResource определяет объект, который на самом деле извлекает сетевой ресурс
import Java.io.InputStream;
import Java.io.lOException;
import javax.microedition.io.Connect ion;
import javax.microedition.io.Connector;
import javax.microedition.io.HttpConnection;
import javax.microedition.Icdui.Displayable;
/**
Данный класс определяет объект helper, используемый классом
ResourceDisplay. Он создает соединение с ресурсом HTTP,
посылает запрос и получает ответ. Он размещает ответную
метаинформацию в буфере. Этот класс предоставляет метод,
который дает возможность другому объекту получать эту информацию
как объект String асинхронно. Этот класс также записывает результат
диагностики в стандартный вывод с целью демонстрации.
Результат появится в окне эмулятора J2MEWTK.
Обратите внимание, что этот класс реализует Runnable.
Он может использоваться программой для выполнения
работы асинхронно, контролируемый нитью, отличной от
основной нити приложения. В данной демонстрации соединения
отдельная нить не порождает подпроцесс контролирования
данного экземпляра, поскольку экземпляр ResourceDisplay,
который использует данный экземпляр, уже контролирует отдельная нить.
**/
public class HttpResource implements Runnable
private static Displayable instance;
// URI, представляющий выбранный ресурс.
private String uri;
// Буфер для поддержки информации ресурса.
private StringBuffer contents = new StringBuffer();
// Соединение с ресурсом. private Connection conn;
// Ссылка на HTTP-соединение, private HttpConnection httpConn;
// Входной поток соединения, private InputStream is;
// Значение поля атрибута статуса HTTP. private int status = -1;
/**
Конструктор.
@pararc uri URI, указывающий выбранный ресурс.
*/
public HttpResource (String uri)
{
super ();
this.uri = uri;
}
private String userAgentID ()
{
StringBuffer buf = new StringBuffer();
String config =
System.get Property("microedition.configuration");
String profile =
System.get Property("microedition.profiles");
buf.append("Configuration/"); buf.append(config); buf.append!" Profile/");
buf.append(profile); return buf . toStrir.g () ; )
/**
Запускает данный объект. Соединяется с URI,
посылает запрос, получает отклик и анализирует ответное сообщение.
*/
public void run()
System.out.println("Connection class name = " + conn.getClass().getName ());
connect () ; parse () ;
System.out.println(gecResourceMetalnfo() ) ;
try conn.close();
}
catch (lOException ioe) System.out.println(ioe.getMessage()) ;
ioe.printStackTrace();
}
}
/**
Соединяется с исходным сервером, который поддерживает URI.
Если произошло исключение во время соединения, этот метод
Перехватит его и не выдаст указания на ошибку, за исключением
Записи в стандартном результате диагностики.
*/
protected void connect!)
}
try
}
while (true)
{
// Соединение находится в состоянии «установка». conn = Connector.open(uri);
httpConn = (HttpConnection) conn;
httpConn.setRequestProperty("method", HttpConnection.HEAD);
httpConn.setRequestProperty("User-Agent", userAgentID());
// Соединение находится в состоянии «установлено». if (resourceRelocated())
{
uri = httpConn.getHeaderField("location");
// Соединение находится в состоянии «отключено» после
// вызова close().
conn.close();
}
else
}
breaX;
*/
if (serverError())
{
conn.close () ; return;
}
// Соединение находится в состоянии «установлено», is = httpConn.openlnputStream ();
System.out.println("Input stream class name = " + is.getClassO .get Name () ) ;
int responseCode = httpCcnn.getResponseCode ();
printResponseCode (responseCode) ; catch (lOExceptior. ioe)
{
contents.append(ioe.getMessage());
System.out.println(ioe.getMessage());
ioe.printStackTrace() ;
}
}
private boolean resourceRelocated()
{
boolean relocated = false; try
}
status = httpConn.getResponseCode();
if (status == HttpConnection.HTTP_MOVED_TEMP II
status == HttpConnection.HTTP_MOVED_PERM II
status == HttpConnection.HTTP_TEMP_REDIRECT)
{
relocated = true;
}
}
catch (lOException ioe)
}
System.out.println(ioe.getMessage() ) ;
ioe.printStackTrace() ;
}
return relocated;
}
private boolean serverError ()
{
boolean error = false;
try
{
status = httpConn.getResponseCode();
if ((status == HttpConnection.HTTP_NOT_IMPLEMENTED)
If (status == HttpConnection.HTTP_VERSION)
If (status == HttpConnection.HTTP_INTERNAL_ERROR)
If (status = = HttpConnection.HTTP_GATEWAY_TIMEOUT)
If (status == HttpConnection.HTTP_BAD_GATEWAY))
}
error = true; } }
catch (lOException ioe)
{
error = true;
System.out.println(ioe.getMessage()) ;
ioe.printStackTrace() ;
}
return error;
}
private void parse()
(
if (httpConn == null) return;
String protocol = httpConn.getProtocol();
contents.append("Protocol: " t protocol + "\n");
String type = httpConn.getType();
content's . append ("Type : " + type + "\n");
String encoding = httpConn.getEncoding ();
contents.append("Encoding: " + encoding + "\n");
long length = httpConn.getLength ();
contents.append("Length: " + length + "\n");
String uri = httpConn.getURL();
contents.append("URL: " + uri + "\n");
String host = httpConn.getHost();
contents.append("Host: " + host + "\n");
String query = httpConn.getQuery();
contents.append("Query: " + query + "\n");
String requestMethod = httpConn.getRequestMethod();
contents.append ("Method: " + requestMethod + "\n");
}
private void printResponseCode(int code)
{
System.out.print("Response code :
**/
switch (code) case HttpConnection.HTTP_ACCEPTED:
Systern.out.print In("HTTP_ACCEPTED"); break;
case HttpConnection.HTTP_BAD_GATEWAY:
Systern.out.print In("HTTP_BAD_GATEWAY"); break;
case HttpConnection.HTTP_BAD_METHOD:
Systern.out.print In("HTTP_BAD_METHOD") ; break;
'case HttpConnection.HTTP_BAD_REQUEST:
Systern.out.print In("HTTP~BAD_REQUEST"); break;
case HttpCo-.nection.HTTP_CONFLICT:
System.out.println("HTTP_CONFLICT"); break;
case HttpConnection.HTTP_CREATED:
System.out.print In("HTTP_CREATED"); break;
case HttpConnection.HTTP_FORBIDDEN:
System.out.print In("HTTP_BAD_FORBIDDEN"); break;
case HttpConnection.HTTP_GATEWAY_TIMEOUT:
System.out.print In("HTTP_GATEWAY_TIMEOUT"); break;
case HttpConnection.HTTP_GONE:
Systern.out.print In("HTTP_GONE"); break;
case HttpConnection.HTTP_NO_CONTENT:
System.out.println("HTTP_NO_CONTENT"); break;
case HttpConnection.HTTP_NOT_ACCEPTABLE:
Systern.out.print In("HTTP_NOT_ACCEPTABLE"); break;
case HttpConnection.HTTP_NOT_FOUND:
System.out.print In("HTTP~NOT_FOUND"); break;
case HttpConnection.HTTP_OK:
System.out.println("HTTP_OK"); break;
case HttpConnection.HTTP_PROXY_AUTH:
Systern.out.print In("HTTP_PROXY_AUTH"); break;
case HttpConnection.HTTP_UNAVAILABLE:
Systern.out.print In("HTTP_UNAVAILABLE"); break;
case HttpConnection.HTTP_VERSION:
System.out.print In("HTTP_VERSION"); break; default:
System.out.println (); ;. }
/**
Получает метахнформацию ресурса.
@выдает метаянформацию, возвращенную
исходным сервером в ответном сообщении.
*/
public String getResourceMetalnfо()
}
return contents.toString();
}
}
Четыре класса представлены в примере, показанном в листингах 8.1 - 8.4:
Класс ConnectionDemo определяет MID-лет. Он отображает форму (определяемую классом URIEntry), которая приглашает пользователя ввести URI. Класс HttpResource обрабатывает процессы установки соединения, посылки запроса и получения и анализа ответа. Класс ResourceDisplay отображает результаты. Класс HttpResource содержит набор основных кодов - то есть сетевой код. Программа создает один экземпляр данного класса для каждого установленного соединения.
Программа действует следующим образом. Пользователь вводит URI в текстовое поле объекта URIEntry. Объект URIEntry создает экземпляр класса ResourceDisplay при получении команды до, введенной пользователем, что означает: «Иди и принеси указанный ресурс». Это происходит в основной нити обработки событий. Объект URIEntry затем создает отдельную нить для контролирования остальной части выполнения экземпляра ResourceDisplay.
Экземпляр ResourceDisplay создает экземпляр класса HttpResource для выполнения работы по извлечению ресурса. Эта работа осуществляется асинхронно в новой созданной нити. Новая нить контролирует следующие этапы:
Все эти этапы могут занимать много времени. Если они исполнялись нитью обработки событий, которая посылала команды в приложение, реализации MIDP придется подождать, пока выполнение вышеупомянутых этапов не завершится, прежде чем она сможет делать что-либо еще.
Это использование нитей является важной идиомой. Цель приложений - избежать выполнения продолжительной обработки команд в методе commandAction(). Эта обработка может блокировать работу на недопустимо длинные периоды времени, как, например, при ожидании ответа с сервера HTTP. Важно, чтобы каждый CommandListener получал данные РЗ своего метода commandActionO «как можно быстрее». Например, в программе, показанной в листинге 8.1, вызов Connector.open() блокирует работу, пока не получит ответ или пока не выйдет время. Временной интервал по умолчанию составляет около 15 секунд в эмуляторе J2MEWTK. Вероятно, реализация MIDP не может быть блокированной от выполнения какой-либо обработки событий так долго.
Класс HttpResource определяет API, который поддерживает получение ресурсов в отдельной нити. Он реализует Runnable и определяет его обработку в методе run(). В нашем примере эта возможность на самом деле не используется, поскольку вторая нить начинает выполнение с методом run() класса ResourceDisplay, который затем вызывает метод HttpRespource.run(). Класс HttpResource может быть использован, однако, в другом приложении, и его реализация Runnable отражает его поддержку многонитевого исполнения.
Объекты соединений. Как вы знаете, различные интерфейсы в структуре общих соединений представляют различные типы соединений. Однако это конкретные реализации данных интерфейсов, которые на самом деле предоставляют соединению его свойства и возможности. Сейчас самое подходящее время более внимательно взглянуть на реализации, стоящие за этими интерфейсами.
Я ссылался на класс Connector как на производящий соединение. Более точно, метод Connector.open() реализует фабричный метод образца проектирования. Для получения более подробной информации по данному и другим образцам проектирования смотрите «Образцы проектирования» (Design Patterns) от «Gamma et al.». Вы пересылаете в класс Connector сформированный в общем виде адрес некоторого ресурса, с которым вы хотите установить соединение. Этот URI указывает схему - тип желаемого соединения - но, с другой стороны, извлекает подробную информацию о соединении, связанную с протоколом. Производитель соединения пересылает обратно объект, чей класс реализует протокол, представленный полем схемы запроса соединения.
Класс этого объекта реализует интерфейс, который определяет тип установленного соединения. Тип внедряемого класса абстрактен, поскольку вы ссылаетесь на объект с помощью ссылки на тип интерфейса. Например, объект соединения, выдаваемый в листинге 8.4, реализует интерфейс HttpConnection. Взгляните на следующие строчки кода, расположенные в методе HttpResource.connect ().
Connection conn;
HttpConnection httpConn;
. . .
conn = Connector.open(uri);
httpConn = {HttpConnection) conn;
. . . .
Первый оператор выдает объект соединения. URI указывает схему http. Текущий объект соединения больше чем просто Connection, это HttpConnection. Поэтому вы можете не рискуя создать ссылку на объект, чей тип - HttpConnection. Вы можете сделать это, потому что фабричный метод выдает объект, чей класс реализует HttpConnection, a не просто Connection. Этот объект отличается от объекта, который был бы выдан при других значениях поля схемы в вызове Connector.ореn().
Первый оператор, показанный в следующей выдержке из метода HttpResource.run(), выдает полностью определенное имя конкретного класса, который реализует интерфейс HttpConnection:
public void run ()
System.out.println("Connection class name = " +
conn.getClass() . get Name () ) ;
connect () ;
parse () ;
...
}
Если вы запустите эту программу на эмуляторе Sun J2ME Wireless Toolkit, вы увидите, что в следующих выходных данных выводится имя класса, который является частью реализации J2ME Sun, которая используется эмулятором Sun J2ME Wireless Toolkit:
com.sun.midp.io.j2me.http.Protocol
Если вы запустите программу, показанную в листингах 8.1 - 8.4, на эмуляторе другого производителя, вы увидите другое имя класса. Таким образом опознается реализация данного производителя интерфейса HttpConnection. Все определяемые протоколом классы зависят от реализации.
Модель состояний соединения HTTP. Соединения HTTP могут находиться в одном из трех состояний в течение их жизненного цикла. Эта модель состояний отражает природу запроса-отклика протокола HTTP. Это следующие три состояния:
На рисунке 8.3 показана диаграмма перемещения из состояния в состояние объектов соединения HTTP. Объект соединения существует в состоянии установки при создании его экземпляра. На данный момент строка запроса не была создана. Чтобы создать запрос, вы должны установить метод HTTP и заголовки запроса. Эти значения устанавливаются с помощью методов, перечисленных в таблице 8.6. Прежде чем соединение сможет войти в состояние «установлено», - прежде, чем оно пошлет запрос серверу и получит ответ, - оно должно установить параметры запроса HTTP, то есть создать сообщение запроса. Вызов этих методов, однако, не приведет к переходу в другое состояние.
Соединение переходит в состояние «установлено», когда вызваны любые из методов, перечисленных в таблице 8.7. Состояние установленного соединения представляет собой период между временем, когда запрос был послан на сервер, и временем, когда либо клиент, либо сервер прервали соединение. Вы можете видеть, что все методы, показанные в таблице 8.7, работают с извлечением данных из ответного сообщения. Чтобы извлечь данные, соединение с сервером должно быть действующим, чтобы клиент получил ответное сообщение.
Рисунок 8.3. Объекты HttpConnection переходят в три различных состояния во время своего существования
Таблица 8.6. Методы интерфейса HttpConnection для создания запроса HTTP
Название метода HttpConnection | Описание |
void setRequestMethod (String method) | Устанавливает метод запроса HTTP, либо HEAD, либо POST, либо GET |
void setRequestProperty (String key, String value) |
Включает в запрос указанное поле заголовка со значением, установленным на value |
Название метода HttpConnection | Описание |
InputStream openlnputStream () | Открывает и выдает ссылку на InputStream (происходит от InputConnection) |
OutputStream openOutputStream() | Открывает и выдает OutputStream для соединения (происходит из OutputConnection) |
DatalnputStream openData!nputStream( ) | Открывает и выдает ссылку на DatalnputStream (происходит из InputConnection) |
DataOutputStream openDataOutputStream() | Открывает и выдает ссылку на DataOutputStream (происходит изOutputConnection) |
long getDate() | Получает значение поля заголовка date |
String getEncoding () | Получает строку, которая описывает шифрование содержимого в ответе (происходит от ContentConnection] |
long getExpiration ( ) | Получает значение поля заголовка expires |
String getHeaderField (String name) | Получает значение указанного поля заголовка |
long getHeaderFieldDate (String name, long def) | Получает значение указанного поля заголовка. Значение анализируется как число |
String getHeaderFieldlnt (String name, int def) | Получает значение указанного поля заголовка. Значение анализируется как число |
String getHeaderFieldKey (int n) | Получает указанное поле заголовка. Аргумент представляет собой индекс поля заголовка |
long getLastModif ied ( ) | Получает значение поля заголовка last-modified |
long getLength() | Извлекает длину поля заголовка. |
int getResponseCode ( ) | Получает код состояния отклика HTTP |
String getResponseMessage ( ) | Получает ответное сообщение HTTP |
String getType() | Получает тип содержимого, предоставляемого сервером (происходит из ContentConnection) |
Когда соединение находится в состоянии «установлено», вы можете лишь извлекать из него данные либо закрыть его. Вы можете задействовать методы, перечисленные в таблицах 8.7 и 8.9. Методы, показанные в таблице 8.8, извлекают различные части ответа HTTP, за исключением метода close (), который разрывает соединение.
Если соединение находится в состоянии «установлено», вы можете больше не активизировать методы, показанные в таблице 8.6. Вы не можете переустановить параметры запроса, что означает, что вы не можете снова использовать объект соединения для доступа к нескольким различным URI. Вы вынуждены создавать экземпляр нового соединения, пересылая новый URI в вызов Connector.ореп(). Кстати, либо клиент может прервать соединение после получения отклика, либо удаленный сервер может разорвать соединение послелосылки этого отклика.
Обратите внимание, что в листинге 8.4 порядок, в котором поля заголовков вставляются в сообщения запроса или извлекаются из ответного сообщения сервера, несущественен. Класс соединения имеет дело с абстракциями создания правильно сформированных сообщений HTTP и анализа ответов HTTP.
Таблица 8.8. Методы интерфейса HttpConnection, вызываемые в состоянии «установлено»
Название метода HttpConnection | Описание |
void close () | Прерывает соединение (происходит из интерфейса Connection) |
String getFile() | Получает поле <file> URL данного соединения |
String getHostO | Получает поле <host> URL данного соединения |
int getPortO | Получает поле <port> URL данного соединения |
String getProtocol () | Получает поле <protocol> URL данного соединения |
:" i ing getQuery () | Получает строку запроса URL данного соединения |
String getRequestMethodf) | Получает текущий метод запроса (GET, POST и так далее) |
String getRequestProperty (String key) | Получает значение свойства указанного общего запроса данного соединения |
String getRef() | Получает поле <ref> URL данного соединения |
String getURL() | Получает полный URL данного соединения как строковое значение |
Использование соединений содержимого соединений. Сила, стоящая за использованием стандартных механизмов соединений содержимого соединений, заключается в том, что не требуется собственного проектирования для создания либо механизма доступа, либо согласованного формата полезного содержимого сообщений. Эта стандартизация служит мотивом поддержки механизма соединения HTTP в MIDP. HTTP является наиболее распространенным стандартным протоколом программного уровня в Интернете на сегодняшний день. Он дает вам возможность получать доступ к большому количеству разнообразных сетевых служб, поскольку поддерживает транспортировку произвольных данных с помощью своего механизма тегирования типа MIME.
Соединения HTTP могут транспортировать множество различных видов содержимого, такого, как HTML и XML. Кроме того, HTTP может использоваться как упаковщик для туннелирования других данных протокола уровня приложений. Вы, таким образом, имеете удобный механизм передачи данных для приложений клиент-сервер.
HTTP широко используется серверами как механизм передачи множества различных служб. Службы могут быть реализованы с помощью любой из множества технологий, независимо от того, что они используют HTTP в качестве механизма передачи. Службы могут быть реализованы с помощью сервлетов Java, Java Server Pages (JSP), Pearl scripts, CGI и так далее.
Модель сервлетов является особенно мощной, поскольку сервлеты написаны на Java и легко стыкуются с другими технологиями Java enterprise, они также без проблем взаимодействуют с клиентскими технологиями. Кроме того, сервлетные системы поддерживаются стандартными Web-серверами и могут без труда создавать выводимые данные в различных форматах. В главе 11 вы узнаете, как порталы беспроводного Интернета используют эти технологии для построения служб для мобильных устройств.