Некоторое время назад я опубликовал на нашем ресурсе матераил о Google Web Toolkit - одном из замечательнейших творений команды Google. Напомню, что этот инструмент позволяет писать сайты не зная даже толком HTML. Не нужно заморачиваться тем, что разные браузеры по-разному интерпретируют интернет-странички, не нужно увязывать в единую систему кучу разнородных файлов. Правда, нужно знать Java. Но это, скорее достоинство, чем недостаток, потому что разве не прекрасно, когда клиент и сервер пишутся на одном и том же языке? Но достоинства GWT для Java-программиста на этом не заканчиваются. Из браузера можно обращаться к методам на удаленной машине почти так же просто, как к локальным. Об этом сегодняшний материал.
Вызов удаленных процедур (Remote Procedure Call или сокращенно RPC) - очень старая и, как оказалось, живучая концепция. Изобретена она была в недрах корпорации Sun еще в 80-х. Линуксоидам RPC хорошо знакомы по системе NFS, которая позволяет монтироваль удаленные файловые системы и пользоваться ими как локальными. Смысл RPC вот в чем. Допустим, у вас есть мощный сервер, обрабатывающий большую базу данных. И есть слабое портативное устройство, запрашивающее у него информацию. Допустим с этого устройства обращаясь к серверу, нужно найти фамилию человека по номеру паспорта. Можно, конечно, организовать систему в виде базы данных и послать серверу соответствующий SQL-запрос. Но, во- первых, не всегда можно "светить" структуру базы данных. Во-вторых, на стороне сервера, помимо SQL-запроса, могут потребоваться дополнительные действия, в третьих, не смотря на то, что эту задачу можно решить кучей способов, самым изящным будет все-таки, вызов метода типа
Passrort passp = getPassport(); FIO fio = remote.getFIO(passp);
На то они и языки программирования высокого уровня, чтобы приблизить общение человека с компьютером к понятным человеку конструкциям. Это особенно ценно, когда речь идет о разделении труда между программистами. Договариваются о названии процедур и структуре классов и реализуют: один человек - клиентскую часть, другой - серверную.
Концепция RPC развивалась бурно. Уже в ранних версиях Java появился пакет rmi, который позволял выполнять удаленные процедуры. Позднее возникли такие вещи, как SOAP, DCOM, CORBA. Всё это вариации на тему RPC. Особенно интересно использовать CORBA. Для нее вообще безразлично, на каком языке люди пишут. В свое время я реализовал проект, где клиент был написан на Visual Basic'e (царство ему небесное), сервер - на Java и они прекрасно и очень прозрачно общались посредством CORBA.
Было бы странно, если бы Google не включила в свой веб-инструментарий накое мощное средство, как RPC. Действительно, допустим перед нами стоит задача создать нечто вроде гостевой книги. При реализации этой затеи обычными средствами нужно на стороне клиента городить форму, причем обязательно с методом post, а на стороне сервера вообще изрядно попотеть, разбирая присланные данные. В помощью RPC код на стороне клиента и на стороне сервера будет выглядеть примерно одинаково:
public void putMessage(String sender, String subj, String message);
Дальнейшее изложение базируется на одной одной англоязычной статье и собственном опыте.
Начало начал для любого удаленного вызова процедуры - создание интерфейса. Это такой особый абстрактный код, который нужен не для программирования конкретных действий, а для обозначения правил обмена данными между клиентом и сервером: как будут называться методы, какого типа будет возвращаемое значение и какие аргументы будут переданы. В GWT интерфейс должен расширять уже имеющимйся в API интерфейс com.google.gwt.user.client.rpc.RemoteService.
import com.google.gwt.user.client.rpc.RemoteService;
public interface MyService extends RemoteService
{
public String myMethod (String s);
}
Поскольку передавать данные серверу мы будем не абы как, а через механизм HTTP, вообще-то не предназначенный для таких дел, Google вводит еще одно передаточное звено - асинхронный интерфейс. Его тоже нужно создать:
import com.google.gwt.user.client.rpc.AsyncCallback; public interface MyServiceAsync { public void myMethod(String s, AsyncCallback callback); }
Знатоки Java уже видят странную вещь: куда же делось возвращаемое значение типа String? И что это за AsyncCallback? А вот он-то как раз и отвечает за "выковыривание" возвращаемого значения из удаленной процедуры. Дело в том, что ответ по HTTP приходит с некоторой задержкой, измеряющейся иногда десятком секунд. Поскольку GWT - всего лишь надстройка над JavaScript, прямая реализация процедуры могла бы привести к зависанию браузера. Вот вызов удаленных процедур и организовали в форме отдельных тредов (ака "ниток") посредством асинхронных обработчиков. При этом такие обработчики еще и ошибки отлавливать умеют. AsyncCallback - абстрактный класс, в котором программист должен самостоятельно реализовать два метода: onSuccess(Object obj) и onFailure(Throwable thr). При этом obj - это и есть тот искомый объект, который доставляется от сервера. Вот как это реализуется:
MyServiceAsync svc = (MyServiceAsync) GWT.create(MyService.class); ServiceDefTarget endpoint = (ServiceDefTarget) svc; endpoint.setServiceEntryPoint("/myService"); AsyncCallback callback = new AsyncCallback() { public void onSuccess (Object result) { RootPanel.get().add(new HTML(result.toString())); } public void onFailure (Throwable ex) { RootPanel.get().add(new HTML(ex.toString())); } }; svc.myMethod("Do Stuff", callback);
Часть кода я сократил, чтобы сконцентрировать внимание на том, что имеет отношение к удаленным процедурам. Многие, кто еще не знаком с GWT и дочитал до этого места, может быть даже пришли к выводу, что всё это большой геморрой. Не торопитесь с выводами. Посмотрите зато как всё легко и просто делается на стороне сервера:
import org.hanson.gwt.client.MyService; import com.google.gwt.user.server.rpc.RemoteServiceServlet; public class MyServiceImpl extends RemoteServiceServlet implements MyService { public String myMethod (String s) { return "You sent us '" + s + "'"; } }
Назовите мне другое средство, которое позволяет так прозрачно реализовывать код на стороне сервера и я признаю, что потратил напрасно два часа на написание этой статьи.
Поскольку Java-код на стороне сервера - это всего лишь сервлет (хотя и существенно усовершенствованный Google'м), то путь к нему нужно прописать обычным для таких серверов как Tomcat или JBoss способом в файле web.xml:
<web-app xmlns="http://java.sun.com/xml/ns/j2ee" version="2.4"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http:/java.sun.com/dtd/web-app_2_3.dtd">
<servlet>
<servlet-name>hello</servlet-name>
<servlet-class>MyServiceImpl</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>hello</servlet-name>
<url-pattern>/myService</url-pattern>
</servlet-mapping>
</web-app>
В общем-то как говорили древние латинцы, Sapienci sat. Что в переводе на русский означает "Без труда не выловишь и рыбку из пруда" :).


Прикольная статейка пиши
Прикольная статейка пиши еще
Слышал новость : Сегодня(20.04.2009) корпорация Oracle и компания Sun Microsystems объявили о достижении договоренности, согласно которой Oracle выкупит акции Sun по цене в 9,5 USD за акцию. Общая сумма сделки составит около 7,4 миллиардов USD. Сообщается, что совет директоров Sun Microsystems единогласно одобрил сделку с Oracle. Завершение процедуры поглощения запланировано на это лето. Интересно что будет с java :) :) :) http://www.oracle.com/us/corporate/press/018363
Как говорит герой популярного
Как говорит герой популярного молодежного сериала: "Чё-то я очкую". Не нравится мне всё это, мелкософтщиной какой-то попахивает. Не пришлось бы на какой-нибудь другой язык переключаться. Впрочем, нет худа без добра: давно мечтал на C++ всерьез писать. Так, чтобы "./configure && make && make install" :). Сишник-то пока, слава Богу, ничьей собственностью не является.
Отправить комментарий