• Nenhum resultado encontrado

Exemplo de Aplica¸c˜ ao: Cat´alogo Telefˆ onico

A fim de melhor ilustrar a utiliza¸c˜ao de RME, ´e mostrada nesta se¸c˜ao uma aplica¸c˜ao simples, desenvolvida para a plataforma J2ME, que utiliza invoca¸c˜ao remota de m´etodos para efetuar consultas a um cat´alogo telefˆonico. O objetivo desta aplica¸c˜ao ´e permitir que usu´arios de celu- lares possam efetuar consultas a um banco de dados em que nomes de pessoas est˜ao associados a n´umeros de telefone. Tal banco de dados foi implementado como um objeto remoto, e as consultas sobre ele s˜ao realizadas via invoca¸c˜ao remota de m´etodos.

Todo objeto remoto, em RME, deve implementar a interface Remote. Tamb´em em Java RMI objetos remotos devem implementar uma interface que possui este nome. Esta interface n˜ao define nenhum m´etodo; sua principal utilidade ´e tornar transparente para o usu´ario a utiliza¸c˜ao

import rme.*; import arcademis.*;

public interface PhoneCatalogue extends Remote { public PhoneAddress getPhoneAddress(String name)

throws ArcademisException; }

Figura 4.20: Interface desenvolvida para um cat´alogo telefˆonico eletrˆonico.

import arcademis.*;

public class PhoneAddress implements Marshalable { private String name = null;

private String phoneNumber = null; private String address = null;

public PhoneAddress(String name, String phoneNumber, String address){ this.name = name;

this.phoneNumber = phoneNumber; this.address = address;

}

public String getName() {...} public String getPhoneNumber() {...} public String getAddress() {...} public boolean equals(Object o) {...} public String toString() {...}

public void marshal(Stream b) throws MarshalException { b.write(phoneNumber);

b.write(name); b.write(address); }

public void unmarshal(Stream b) throws MarshalException { this.phoneNumber = (String)b.readObject();

this.name = (String)b.readObject(); this.address = (String)b.readObject(); }

}

Figura 4.21: Classe que representa entradas em um cat´alogo telefˆonico eletrˆonico. de stubs em vez da real implementa¸c˜ao dos objetos cujos servi¸cos deseja-se invocar. O servi¸co de nomes devolve objetos do tipo Remote como resultado de consultas. A classe arcademis.Stub, ancestral de todos os stubs em RME tamb´em implementa a interface Remote. Assim, n˜ao existem problemas, em rela¸c˜ao ao sistema de tipos de Java, para atribuir a stubs o resultado de buscas por objetos remotos. A interface definida para a aplica¸c˜ao deste exemplo pode ser vista na Figura 4.20. Nessa interface, somente um m´etodo ´e definido: getPhoneAddress. Tal opera¸c˜ao retorna, para cada consulta efetuada com sucesso `a lista telefˆonica, um objeto do tipo PhoneAddress, que cont´em os dados referentes `a pessoa pesquisada.

A implementa¸c˜ao da classe PhoneAddress pode ser vista na Figura 4.21. Uma vez que se tenciona transmitir objetos deste tipo como respostas de invoca¸c˜oes remotas, a classe Phone- Addressprecisa implementar a interface Marshalable, e, em conseq¨uˆencia, ela deve prover um corpo para os m´etodos marshal e unmarshal. Objetos do tipo PhoneAddress possuem apenas trˆes atributos. O processo de serializa¸c˜ao consiste em copiar tais valores para uma cadeia de bytes. O processo inverso, executado pelo m´etodo unmarshal, consiste em preencher os valores dos atributos com informa¸c˜oes lidas de uma cadeia de bytes.

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

public class PhoneBook extends rme.server.RmeRemoteObject implements PhoneCatalogue {

Hashtable h = null; public PhoneBook() {

h = new Hashtable(); }

public PhoneAddress getPhoneAddress(String name) { PhoneAddress addr = (PhoneAddress)h.get(name); return addr;

}

private void insert(String name, String number, String address) { PhoneAddress addr = new PhoneAddress(name, number, address); h.put(name, addr);

}

public void readFile(String fileName) throws IOException { // fills the hashtable with information from fileName. }

}

Figura 4.22: Implementa¸c˜ao de um cat´alogo telefˆonico eletrˆonico.

A implementa¸c˜ao do cat´alogo telefˆonico ´e simples: trata-se de uma classe que encapsula uma tabela em que est˜ao associados a cada nome de pessoa um n´umero telefˆonico. Tal implementa¸c˜ao ´e mostrada na Figura 4.22. Observe que esta classe destina-se a ser utilizada remotamente, por´em ela n˜ao possui qualquer c´odigo extra a lhe garantir contato com as primitivas de comunica¸c˜ao do sistema operacional. A n˜ao ser por estender RmeRemoteObject, esta classe em nada difere de uma classe que somente ´e utilizada localmente. Toda a implementa¸c˜ao necess´aria para que invoca¸c˜oes remotas possam ser recebidas, processadas e respondidas encontra-se no corpo da classe Rme- RemoteObject. Apenas o m´etodo readFile n˜ao foi integralmente mostrado na Figura 4.22. Tal m´etodo permite preencher a tabela com pares formados por um nome de pessoa e um objeto do tipo PhoneAddress, cujo conte´udo foi lido a partir de um arquivo.

´

E necess´ario implementar um servidor para o cat´alogo telefˆonico. Tal servidor ter´a por fun¸c˜ao instanciar um objeto do tipo PhoneBook e preencher tal objeto com tuplas formadas por nomes, n´umeros telefˆonicos e endere¸cos residenciais. Al´em disto, cabe ao servidor inicializar as entidades respons´aveis pelo recebimento de chamadas remotas. A implementa¸c˜ao de tal elemento pode ser vista na Figura 4.23. A configura¸c˜ao do ORB tem lugar nas linhas 9 e 10 dessa figura. No programa apresentado, est´a sendo utilizada a configura¸c˜ao padr˜ao fornecida por RME, contudo, outras configura¸c˜oes s˜ao perfeitamente poss´ıveis. Com tal prop´osito, poder-se-ia implementar outra classe de configura¸c˜ao, ou poder-se-ia estender a classe RmeConfigurator, ou ainda poder- se-ia efetuar modifica¸c˜oes no c´odigo desta classe. A constata¸c˜ao de que, para ser modificado todo o comportamento da aplica¸c˜ao distribu´ıda, basta alterar uma linha de c´odigo (a linha 9 da Figura 4.23) torna n´ıtido o caracter flex´ıvel e reconfigur´avel de Arcademis e da plataforma RME.

Para completar o exemplo apresentado nesta se¸c˜ao, ´e necess´ario que seja mostrada a im- plementa¸c˜ao de uma aplica¸c˜ao cliente, isto ´e, um programa que utiliza os servi¸cos fornecidos

1: public class Server {

2: public static void main(String args[]) { 3: if(args.length != 2) {

4: System.err.println("Sintaxe: java PhoneBook objName fileName"); 5: System.exit(1);

6: } 7: else { 8: try {

9: rme.RmeConfigurator c = new rme.RmeConfigurator(); 10: c.configure();

11: PhoneBook o = new PhoneBook();

12: rme.naming.RmeNaming.bind(args[0], o); 13: o.activate(); 14: o.readFile(args[1]); 15: } catch (arcademis.ArcademisException e) { 16: e.printStackTrace(); 17: } catch (arcademis.concrete.MalformedURLException e) { 18: e.printStackTrace(); 19: } catch (rme.naming.AlreadyBoundException e) { 20: e.printStackTrace(); 21: } catch (java.io.IOException e) { 22: e.printStackTrace(); 23: } 24: } 25: } 26:}

Figura 4.23: Implementa¸c˜ao de um servidor de m´etodos remotos.

pela classe PhoneBook, vista na Figura 4.22. Tal classe foi implementada sobre a plataforma J2ME, e pode ser utilizada sobre um emulador de celular, ou sobre um dispositivo real, caso este suporte CLDC. Dado que tal implementa¸c˜ao ´e constitu´ıda por um n´umero relativamente grande de linhas de c´odigo, ela ´e apresentada em partes. A estrutura geral do c´odigo pode ser vista na Figura 4.24. O m´etodo construtor e o m´etodo respons´avel pelo tratamento de eventos encontram-se implementados, respectivamente, nas Figuras 4.25 e 4.26.

A aplica¸c˜ao cliente consiste basicamente de um formul´ario no qual podem ser informados o caminho at´e um objeto e um nome para consulta. Na Figura 4.24 foram mostrados apenas os comandos necess´arios para construir o formul´ario, que ´e formado por quatro campos: url, name, phone e addr. A primeira destas entradas especifica a localiza¸c˜ao de um objeto remoto, a qual ´e definida por um endere¸co IP seguido por um nome de objeto. O segundo campo permite que o usu´ario forne¸ca nomes para consulta e os outros dois campos s˜ao utilizados pela aplica¸c˜ao para fornecer os resultados obtidos em uma consulta remota.

O m´etodo construtor pode ser visto na Figura 4.25. O trecho de c´odigo compreendido entre as linhas 8 e 10 diz respeito `a configura¸c˜ao do middleware e `a busca por um objeto distribu´ıdo identificado pelo nome obj e localizado em um host cujo endere¸co IP ´e algol.dcc.ufmg.br/obj. Os demais comandos concernem a inicializa¸c˜ao de outros componentes da aplica¸c˜ao, como a tela gr´afica e bot˜oes de comando.

1: import java.io.*; 2: import javax.microedition.io.*; 3: import javax.microedition.midlet.*; 4: import javax.microedition.lcdui.*; 5: import rme.*; 6: import rme.naming.*; 7: import arcademis.*; 8:

9: public class PhoneBookClient extends MIDlet implements CommandListener {

10: private Display display = null;

11: private PhoneCatalogue phoneBook = null;

12: private Command exitCmd = null;

13: private Command getInf = null; 14: private Form sendScr = null; 15: private TextField url = null; 16: private TextField name = null;

17: private TextField phone = null;

18: private TextField addr = null; 19:

20: public PhoneBookClient() { ... } 21:

22: private Screen showSendScreen() {

23: if(sendScr == null) {

24: sendScr = new Form("Send Message");

25: sendScr.addCommand(exitCmd);

26: sendScr.addCommand(getInf);

27: sendScr.setCommandListener(this);

28: url = new TextField("URL: ", "algol.dcc.ufmg.br/obj", 60, TextField.URL);

29: sendScr.append(url);

30: name = new TextField("Name: ", "", 40, TextField.ANY);

31: sendScr.append(name);

32: phone = new TextField("Phone: ", "0", 20, TextField.ANY);

33: sendScr.append(phone);

34: addr = new TextField("Address: ", "0", 60, TextField.ANY);

35: sendScr.append(addr);

36: }

37: display.setCurrent(sendScr);

38: return sendScr;

39: }

40: public void startApp() {

41: showSendScreen();

42: }

43: public void pauseApp() {

44: }

45: public void destroyApp(boolean unconditional) {

46: }

47: public void commandAction(Command c, Displayable s) { ... } 48:}

1: public PhoneBookClient() {

2: display = Display.getDisplay(this); 3:

4: exitCmd = new Command("Exit", Command.EXIT, 1); 5: getInf = new Command("getInf", Command.OK, 2); 6:

7: try {

8: RmeConfigurator mc = new RmeConfigurator(); 9: mc.configure(); 10: phoneBook = (PhoneCatalogue)RmeNaming.lookup("algol.dcc.ufmg.br/obj"); 11: } 12: catch (Exception e) { 13: e.printStackTrace(); 14: } 15:}

Figura 4.25: M´etodo construtor para a aplica¸c˜ao cliente mostrada na Figura 4.24. A Figura 4.26 apresenta a implementa¸c˜ao do m´etodo commandAction, o qual ´e respons´avel pelo tratamento de eventos que s˜ao disparados pelo usu´ario enquanto este interage com o dis- positivo m´ovel. Dois tipos de eventos s˜ao tratados pelo m´etodo da Figura 4.26: s˜ao eles o encerramento da aplica¸c˜ao e a ativa¸c˜ao de um comando nomeado getInf. CLDC permite que bot˜oes de comando sejam definidos e adicionados `a aplica¸c˜ao a fim de que o usu´ario tenha como solicitar a realiza¸c˜ao de algumas a¸c˜oes. Quando o evento de encerramento ´e acionado, os recur- sos alocados pela aplica¸c˜ao s˜ao liberados de volta para o dispositivo m´ovel. Quando o comando getInf´e acionado, uma consulta ´e realizada sobre o objeto remoto que implementa o cat´alogo telefˆonico. Tal consulta fornece o nome que deve ser informado na caixa de texto name e recebe como resposta um objeto do tipo Address, que cont´em as informa¸c˜oes associadas `aquele nome na lista telefˆonica.