






























Estude fácil! Tem muito documento disponível na Docsity
Ganhe pontos ajudando outros esrudantes ou compre um plano Premium
Prepare-se para as provas
Estude fácil! Tem muito documento disponível na Docsity
Prepare-se para as provas com trabalhos de outros alunos como você, aqui na Docsity
Encontra documentos específicos para os exames da tua universidade
Prepare-se com as videoaulas e exercícios resolvidos criados a partir da grade da sua Universidade
Responda perguntas de provas passadas e avalie sua preparação.
Ganhe pontos para baixar
Ganhe pontos ajudando outros esrudantes ou compre um plano Premium
Apostilas de Computação Científica sobre o estudo da Programação Orientada a Objetos, Desenvolvimento de aplicações distribuídas, Palavras chaves de Java.
Tipologia: Notas de estudo
1 / 38
Esta página não é visível na pré-visualização
Não perca as partes importantes!































Programação orientada a objetos com Java 5.1. Programação cliente-servidor
ordenação correta dos pacotes. Por outro lado, a ausência desses mecanismos permite uma transfe- rência mais rápida. O endereçamento em UDP dá-se como para a programação TCP, usando a classe Java InetAd- dress.
Soquetes UDP
Assim como para o protocolo TCP, UDP estabelece uma conexão entre o processo da aplicação e a rede através de um soquete. Em Java, soquetes UDP são manipulados através de objetos da classe DatagramSocket. O construtor padrão para essa classe cria um soquete local na primeira porta disponível. Alternativa- mente, outro construtor permite especificar o número da porta desejado. Ao contrário da classe Socket, um DatagramSocket não estabelece uma conexão com uma máquina remota, mas simplesmente um acesso local para a rede que pode ser utilizada para enviar e receber pacotes, através dos métodos send() e receive(), respectivamente. Há um método connect() associado a objetos da classe DatagramSocket; no entanto, esse método atua como um filtro, só permitindo enviar ou receber pacotes para ou de um endereço IP ao qual o soquete foi conectado. O método disconnect() permite desconectar um soquete de um destino pré-especificado.
Datagramas
Os pacotes enviados e recebidos através dos soquetes UDP são objetos Java da classe Data- gramPacket. Objetos dessa classe podem ser construídos de duas maneiras, dependendo se serão enviados ou recebidos através do soquete UDP:
Pacotes a enviar. Nesse caso, deve ser utilizado o construtor que incorpora em seus argumentos o arranjo de bytes a enviar, seu tamanho, e o endereço de destino (máquina, especificada pelo seu endereço IP, e porta).
Pacotes a receber. Nesse caso, os argumentos especificam apenas o arranjo de bytes para onde o conteúdo do pacote será transferido e o limite no tamanho do pacote que será recebido nesse arranjo.
Uma vez que um pacote tenha sido recebido, a informação sobre sua origem pode ser obtida através dos métodos getAddress() e getPort(). Os dados efetivamente recebidos podem ser extraídos do pacote usando o método getData(); o método getLength() permite determinar a dimensão dos dados.
Multicast
Um MulticastSocket é uma especialização de um DatagramSocket que permite que uma aplicação receba pacotes datagramas associados a um endereço multicast (classe D, endereços entre 224.0.0.1 e 239.255.255.255). Não é preciso nenhuma funcionalidade especial para apenas enviar datagramas para um endereço multicast.
Programação orientada a objetos com Java 5.1. Programação cliente-servidor
Todos os soquetes multicast que estejam inscritos em um endereço multicast recebem o datagra- ma que foi enviado para esse endereço e porta. Para gerenciar a inscrição de um soquete em um endereço multicast , dois métodos são oferecidos na classe MulticastSocket. O primeiro, joinGroup(InetAddress m), permite à aplicação juntar-se a um grupo mul- ticast. É o método que inscreve o soquete no grupo associado ao endereço multicast especificado como argumento. O outro método, para desligar-se de um grupo multicast , é leaveGroup(InetAddress m), que desconecta o soquete do grupo multicast especificado.
A World Wide Web (WWW ou simplesmente Web) é a primeira concretização de uma rede mun- dial de informação através de computadores. Proposta em 1989 no CERN (Suíça) por Tim-Berners Lee, ela interconecta principalmente documentos hipertexto (expressos em HTML — HyperText Markup Language ) usando a infra-estrutura da Internet para a transferência de informação. Sua difusão expandiu-se principalmente após a popularização de interfaces gráficas com o usuário para navegação em hipertexto, iniciada a partir do lançamento do aplicativo Mosaic no NCSA (EUA). A Web pode ser vista como um serviço de aplicação da arquitetura TCP/IP. Como tal, a arquitetu- ra da Web define um esquema de endereçamento (URL) no nível da aplicação; estabelece protocolos de sessão (soquetes TCP/IP) e apresentação (HTML e auxiliares); define um protocolo (HTTP) no nível da aplicação; e segue o modelo cliente-servidor. As aplicações clientes na Web são usualmente navegadores (browsers) responsáveis pela apresen- tação de documentos HTML e pela solicitação de um recurso a servidores Web. O recurso pode ser um documento HTML ou um arquivo contendo informação texto ou binária (imagem, áudio, vídeo, applet Java, etc), conforme estabelecido pelo elemento que originou a solicitação. Não necessariamente o software navegador precisa saber manipular todos os tipos de recursos, podendo ele ativar rotinas auxiliares de exibição para tipos não reconhecidos. As rotinas auxiliares podem ser ativadas sob a forma de programas executáveis externos ao navegador ou através de plug- ins. O conceito de plug-in foi desenvolvido pela Nestcape, sendo constituído por uma interface de programação (API) padronizada para ativar funcionalidades carregadas dinamicamente. Servidores Web são responsáveis por atender a solicitações de clientes, por default operando na porta notável 80. As funcionalidades básicas de servidores Web incluem: organizar e gerenciar os recursos HTTP; prover acesso seguro a esses recursos; e processar scripts (extensões CGI, por exemplo — ver Seção 5.3). Java também oferece suporte ao desenvolvimento de aplicações sobre a Web usando recursos do pacote java.net. Dentre os conceitos oferecidos pela linguagem Java para a programação distri- buída há uma grande ênfase na programação direcionada para a Web, com suporte para a manipulação de recursos Web através de URL, a manipulação de conexões HTTP, a conversão de strings para o formato de codificação www-urlencoded e suporte à manipulação de conteúdos de diferentes tipos MIME.
Endereçamento por URL
Um endereço localizador uniforme de recursos (URL) é definido por uma seqüência de caracteres que identifica de forma global e precisa um recurso na Web. A forma genérica de um URL é
Programação orientada a objetos com Java 5.2. Acesso a bancos de dados
DELETE: permite que o cliente autorizado remova um recurso mantido pelo servidor.
Um cabeçalho HTTP é composto por uma linha contendo a especificação do serviço e recurso associado, seguida por linhas contendo parâmetros. Um exemplo de requisição gerada por um cliente HTTP é:
GET http://www.dca.fee.unicamp.br/ Accept: text/html, image/gif, image/jpeg User-Agent: Mozilla/3.
para a qual o cabeçalho da resposta poderia ser:
HTTP/1.1 200 OK Date: Wed, 24 Mar 1999 23:23:45 GMT Server: Apache/1.2b Connection: close Content-Type: text/html Content-length: 648 A indicação do tipo de conteúdo do recurso (usada nos parâmetros Accept e Content-Type) seguem a especificação no padrão MIME (Multipurpose Internet Mail Extensions). A classe HttpURLConnection é uma especialização da classe URLConnection. Quando um objeto da classe URL invoca openConnection() é esse o tipo de conexão retornada quando o protocolo é HTTP. Além das funcionalidades de conexões URL, essa classe define várias constantes associadas espe- cificamente ao protocolo HTTP (tais como os códigos de erros) e alguns poucos métodos específicos de conexão HTTP.
Codificação e decodificação de dados
A tradução de strings para o formato esperado por um servidor Web a partir de um formulário, x-www-form-urlencoded , é suportada através da classe URLEncoder. Essa classe oferece o método estático encode(String s), retornando uma string com o conteúdo codificado do argumento. O formato www-urlencoded agrega em uma única string uma série de pares na forma atribu- to=valor separados pelo símbolo ’&’. Nesse formato, espaços são convertidos para o símbolo ’+’ e caracteres com conotação especial — tais como +, = e & — são representados por seqüência de escape ’%xx’ para a representação hexadecimal do valor ASCII do caráter. Assim, o caráter ’=’ que faça parte do nome de um atributo ou parte do conteúdo de um valor será codificado na string na forma ’%3d’. O processo de tradução a partir de uma string nesse formato, que seria o necessário para imple- mentar um serviço em Java que recebesse dados de um formulário, é oferecido pela classe URLDe- coder, através do método estático decode(String).
A linguagem Java vem se destacando como uma alternativa viável para a integração de apli- cações novas e legadas na Internet. Essa infra-estrutura de integração não estaria completa se não contemplasse o acesso a sistemas de bancos de dados.
Programação orientada a objetos com Java 5.2. Acesso a bancos de dados
Um sistema de banco de dados é constituído por uma coleção organizada de dados (a base de dados) e pelo software que coordena o acesso a esses dados (o sistema gerenciador de banco de dados, ou SGBD). Utilizar um sistema de banco de dados ao invés de simples arquivos para armazenar de forma persistente os dados de uma aplicação apresenta diversas vantagens, das quais se destacam:
trabalhando com especificações mais abstratas para a definição e manipulação dos dados;
plos usuários e controle de transações;
dados de cada aplicação seja distinta. Existem soluções para integrar aplicações Java a bancos de dados orientados a objetos e a bancos de dados relacionais. Neste caso, a solução é padronizada através da especificação JDBC.
Um banco de dados relacional organiza seus dados em relações. Cada relação pode ser vista como uma tabela, onde cada coluna corresponde a atributos da relação e as linhas correspondem às tuplas ou elementos da relação. Em uma nomenclatura mais próximas àquela de sistemas de arquivos, muitas vezes as tuplas são denominadas registros e os atributos, campos. Um conceito importante em um banco de dados relacional é o conceito de atributo chave, que permite identificar e diferenciar uma tupla de outra. Através do uso de chaves é possível acelerar o acesso a elementos (usando índices) e estabelecer relacionamentos entre as múltiplas tabelas de um sistema de banco de dados relacional. Essa visão de dados organizados em tabelas oferece um conceito simples e familiar para a estru- turação dos dados, sendo um dos motivos do sucesso de sistemas relacionais de dados. Certamente, outros motivos para esse sucesso incluem o forte embasamento matemático por trás dos conceitos uti- lizados em bancos de dados relacionais e a uniformização na linguagem de manipulação de sistemas de bancos de dados relacionais através da linguagem SQL. Sob o ponto de vista matemático, uma relação é o subconjunto do produto cartesiano dos domí- nios da relação. Sendo um conjunto, é possível realizar operações de conjuntos — tais como união, interseção e diferença — envolvendo duas relações de mesma estrutura. No entanto, um dos pontos mais fortes do modelo relacional está nos mecanismos de manipula- ção estabelecidos pela Álgebra Relacional. Os três principais operadores da álgebra relacional são seleção, projeção e junção. A operação de seleção tem como argumento uma relação e uma condição (um predicado) envol- vendo atributos da relação e/ou valores. O resultado é uma outra relação contemplando apenas as tuplas para as quais a condição foi verdadeira. A operação de projeção tem como argumento uma relação e uma lista com um subconjunto dos atributos da relação. O resultado é outra relação contendo todas as tuplas da relação mas apenas com os atributos especificados. Observe que se a lista de atributos não englobar a chave da relação, o resultado dessa operação poderia gerar tuplas iguais. Sob o ponto de vista estritamente matemático, os elementos duplicados devem ser eliminados, pois não fazem sentido para um conjunto.
Programação orientada a objetos com Java 5.2. Acesso a bancos de dados
Além desses comandos, ALTER TABLE permite modificar a estrutura de uma tabela existente e DROP TABLE permite remover uma tabela. O principal comando da DML de SQL é SELECT. Por exemplo, para obter todos os dados de uma relação utiliza-se a forma básica:
SELECT * FROM table
Através do mesmo comando, é possível especificar projeções e seleções de uma tabela:
SELECT columns FROM table WHERE condition
A condição pode envolver comparações entre atributos e/ou valores constantes, podendo para tanto utilizar comparadores tais como igual (=), maior que (>), menor que (<), maior ou igual que (>=), menor ou igual que (<=), diferente (!= ou <>) e comparadores de strings (LIKE ‘string’, onde ‘string’ pode usar os caracteres ‘_’ e ’%’ para indicar um caráter qualquer os uma seqüência qual- quer de caracteres, respectivamente). As comparações podem ser combinadas através dos conectivos lógicos And, Or e Not. É possível expressar as quatro operações aritméticas (+, -, *, /), tanto para a condição como para a especificação de recuperação dos dados. É possível também especificar a ordem desejada de apresentação dos dados, usando para tal a for- ma SELECT...ORDER BY.... Uma alternativa a esse comando é SELECT...GROUP BY..., que ordena os dados e não apresenta elementos que tenham o mesmo valor para a cláusula de agru- pamento. Uma importante categoria de funções de SQL incluem as funções de agregação, que permitem computar a média (Avg), a quantidade (Count), o maior ou menor valor (Max ou Min) e o total (Sum) das expressões especificadas. Através do mesmo comando Select, é possível especificar consultas envolvendo múltiplas tabelas, como em
SELECT nome, data FROM Pedidos, Clientes WHERE Pedidos.NumCliente = Clientes.NumCliente
Nesse caso, a junção das duas tabelas Pedidos e Clientes é realizada tendo como Num- Cliente como atributo de junção. É possível especificar consultas internas a uma consulta, como em
SELECT NumProduto From Produtos WHERE PrecoUnit > (SELECT Avg(PrecoUnit) FROM Produtos)
Para qualificar os resultados de uma subconsulta, podem ser utilizadas as funções All (a con- dição foi verdadeira para todos os elementos resultantes da subconsulta), Any (verdade para pelo menos um elemento), Exists (verdade se resultado da consulta tem pelo menos um elemento), In (verdade se o valor especificado faz parte do resultado), Not Exists (verdade se subconsulta teve resultado vazio) e Not In (verdade se valor especificado não faz parte do resultado da subconsulta). SQL oferece ainda mecanismos para inserir elementos em uma tabela,
Programação orientada a objetos com Java 5.2. Acesso a bancos de dados
INSERT INTO table (columns) VALUES (values)
para modificar valores de colunas de um elemento,
UPDATE table SET column = value [, column = value]* WHERE condition
e para remover elementos de uma tabela,
DELETE FROM table WHERE condition
SQL pode ser utilizado diretamente pelo usuário, quando o SGBD oferece um interpretador SQL interativo, ou através de comandos embutidos em uma aplicação desenvolvida em uma linguagem de programação. No caso dessa linguagem ser Java, a forma de interagir com o banco de dados é especificado por JDBC.
Java permite o acesso a bancos de dados relacionais através das funcionalidades definidas no pacote java.sql, que define o “produto JDBC”. JDBC é uma API para execução e manipulação de resultados a consultas SQL através de Java. Para desenvolver uma aplicação com Java e bancos de dados relacionais, é preciso ter disponível:
versão 1.1);
Uma vez que esses recursos estejam disponíveis, a aplicação Java tem acesso ao banco de dados relacional através da execução dos seguintes passos:
Driver JDBC
Do ponto de vista da aplicação Java, um driver nada mais é do que uma classe cuja funcionalidade precisa ser disponibilizada para a aplicação. A funcionalidade básica que um driver deve oferecer é especificada através da interface Driver. A classe DriverManager estabelece um conjunto básico de serviços para a manipulação de drivers JDBC. Como parte de sua inicialização, essa classe tentará obter o valor da propriedade
Programação orientada a objetos com Java 5.2. Acesso a bancos de dados
Os métodos da interface ResultSet permitem a manipulação dos resultados individuais de uma tabela de resultados. Métodos como getDouble(), getInt(), getString() e getTime(), que recebem como argumento a especificação de uma coluna da tabela, permitem acessar o valor da coluna especificada na tupla corrente para os diversos tipos de dados suportados. Para varrer a tabela, um cursor é mantido. Inicialmente, ele está posicionado antes do início da tabela, mas pode ser manipulado pelos métodos first(), next(), previous(), last() e absolute(int row). Por exemplo,
ResultSet r = s.executeQuery("Select * from Clientes"); System.out.println("ID NOME"); while (r.next()) System.out.println(r.getString("ClienteID")+ " " + r.getString("Nome")); r.close();
Para lidar com atributos que podem assumir valores nulos, o método wasNull() é oferecido. Ele retorna verdadeiro quando o valor obtido pelo método getXXX() for nulo, onde XXX é um dos tipos SQL. A interface ResultSetMetadata permite obter informação sobre a tabela com o resultado da consulta. Um objeto desse tipo pode ser obtido através da aplicação do método getMetaData() ao ResultSet:
ResultSetMetaData m = r.getMetaData();
Uma vez obtido esse objeto, a informação desejada pode ser obtida através de métodos tais como getColumnCount(), getColumnLabel(), getColumnTypeName() e getColumnTy- pe(). O último método retorna tipos que podem ser identificados a partir de constantes definidas para a classe java.sql.Types. Além da forma Statement, JDBC oferece duas formas alternativas que permitem respecti- vamente ter acesso a comandos SQL pré-compilados (PreparedStatement) e a procedimentos armazenados no banco de dados (CallableStatement).
Exemplo completo
Este exemplo ilustra o mecanismo básico para uma aplicação Java acessar um banco de dados. O objetivo é apresentar o conteúdo da seguinte relação, a tabela “notas” do banco de dados “poojava”:
> java PoojavaDB fname lname activ grd Joao Silva 1 6 Joao Silva 2 7 Pedro Souza 1 8 Pedro Souza 2 5 Maria Santos 1 7 Maria Santos 2 8
Programação orientada a objetos com Java 5.3. Servlets
O resultado acima foi obtido a partir da execução da seguinte aplicação, acessando um gerencia- dor de banco de dados PostgreSQL:
1 import java.sql.*; 2 public class PoojavaDB { 3 public static void main(String[] args) { 4 try { 5 // carrega driver 6 Class.forName("postgresql.Driver"); 7 // estabelece conexao com banco de dados 8 Connection c = 9 DriverManager.getConnection("jdbc:postgresql:poojava", 10 "ricarte",""); 11 // monta e executa consulta 12 Statement s = c.createStatement(); 13 ResultSet r = s.executeQuery("Select * from notas"); 14 // apresenta estrutura da tabela 15 ResultSetMetaData m = r.getMetaData(); 16 int colCount = m.getColumnCount(); 17 for (int i=1; i<=colCount; ++i) 18 System.out.print(m.getColumnName(i) + "\t\t"); 19 System.out.println(); 20 // apresenta resultados da consulta 21 while (r.next()) 22 System.out.println(r.getString(1) + " " + 23 r.getString(2) + " " + 24 r.getInt(3) + "\t\t" + 25 r.getInt(4)); 26 r.close(); 27 // fecha conexao com banco de dados 28 c.close(); 29 } 30 catch (Exception e) { 31 System.err.println(e); 32 } 33 } 34 }
Servlets oferecem uma maneira alternativa a CGI para estender as funcionalidades de um servidor Web. Na verdade, a API de servlet de Java oferece mecanismos adequados à adaptação qualquer servidor baseado em requisições e respostas, mas é em aplicações Web que servlets têm sido mais utilizados.
Programação orientada a objetos com Java 5.3. Servlets
O suporte a servlets é uma extensão padronizada ao pacote Java, não sendo parte da distribuição básica do Java SDK. Assim, quem quiser desenvolver servlets deve obter o JSDK, o Java Servlet Development Kit. Adicionalmente, o servidor Web deve suportar o acesso a servlets , o que pode ocorrer de forma nativa (como no caso do Java Web Server ) ou através de módulos add-on (como no caso de apache). O JSDK inclui as classes que implementam a API de servlets organizadas em pacotes, dos quais os principais são javax.servlet e javax.servlet.http. Adicionalmente, uma aplicação servletrunner permite desenvolver e testar servlets antes de integrá-los a servidores. Os três mecanismos alternativos básicos para criar um servlet são:
Na primeira forma básica de implementar um servlet , estendendo a classe GenericServlet, o método service() deve ser definido. Esse método descreve o serviço que o servlet estará ofere- cendo. Esse exemplo ilustra o código de um servlet que responde à solicitação de serviço com uma mensagem fixa:
1 import javax.servlet.; 2 import java.io.; 3 public class OiServlet extends GenericServlet { 4 public void service(ServletRequest solicitacao, 5 ServletResponse resposta) 6 throws ServletException, IOException { 7 resposta.setContentType("text/plain"); 8 PrintWriter saida = resposta.getWriter(); 9 saida.println("Oi!"); 10 } 11 }
Nesse exemplo, o método getWriter() é utilizado para estabelecer o canal de envio de dados desde o servlet — no caso, um objeto PrintWriter, permitindo o envio de textos. Alternati- vamente, dados binários poderiam ser enviados através de um OutputStream, obtido através do método getOutputStream(). A classe HttpServlet é uma extensão de GenericServlet especificamente projetada para a conexão de servlets a servidores HTTP. Assim, métodos dedicados a lidar com solicitações HTTP, tais como doGet(), doPost() e doPut(), são definidos. A implementação padrão do método service() reconhece qual o tipo de solicitação recebida e invoca o método correspondente.
Programação orientada a objetos com Java 5.3. Servlets
Este exemplo ilustra a utilização de um servlet que envia uma mensagem fixa no corpo de uma página HTML em resposta a uma requisição GET ao servidor Web, usando para tal o método do- Get(): 1 import javax.servlet.; 2 import javax.servlet.http.; 3 import java.io.*; 4 public class OiHttpServlet extends HttpServlet { 5 public void doGet(HttpServletRequest solicitacao, 6 HttpServletResponse resposta) 7 throws ServletException, IOException { 8 resposta.setContentType("text/html"); 9 PrintWriter saida = resposta.getWriter(); 10 saida.println(""); 11 saida.print(""); 12 saida.print("Resposta do servlet"); 13 saida.println(""); 14 saida.println("
Oi!
"); 15 saida.println(""); 16 } 17 }Outros métodos que suportam a interação do servlet através de solicitações HTTP incluem ge- tLastModified(), que é invocado pelo servidor para obter a data da última modificação do “do- cumento” (um número negativo se não houver informação ou long com o número de segundos desde 1 de janeiro de 1970 GMT); e getServletInfo(), que retorna uma string de documentação sobre o servlet , tal como nome, autor e versão. A passagem de dados de um formulário do cliente para o servlet pode se dar através do método getParameter(), que permite obter uma string com o valor do campo especificado. Por exemplo, se um formulário HTML especificasse um campo de texto para entrada do nome do usuário, como em
esse valor poderia ser obtido no código do servlet do exemplo anterior através da invocação String nome = solicitacao.getParameter("username"); Além de getParameter(), o método getParameterValues() retorna um arranjo de strings com todos os valores de um determinado parâmetro. Outros métodos são oferecidos para ob- ter informação das aplicações que estão invocando o servlet , tais como getRemoteHost(), get- ServerName(), getServerPort() e, especificamente para HTTP, getHeaderNames() e getHeader(). A forma de integrar o servlet ao servidor Web é dependente da implementação; por exemplo, alguns servidores especificam um diretório (tal como servlet) onde as classes servlets são con- centradas e a invocação dá-se pela invocação direta da URL, como em http://site/servlet/OiHttpServlet
Programação orientada a objetos com Java 5.4. Programação com objetos distribuídos
Descrever o serviço. Na arquitetura de objetos, a descrição ou especificação de serviços é determi- nada através das interfaces. Em Java, isto é realizado através da especificação oferecida por uma interface.
Implementar o serviço. Isto é realizado através do desenvolvimento de uma classe Java que imple- mente a interface especificada.
Anunciar o serviço. Quando um objeto que implementa o serviço torna-se ativo, é preciso que ele seja registrado em um “diretório de serviços” de forma que potenciais clientes possam localizá- lo.
Sob o ponto de vista do objeto cliente, que vai usar o serviço do objeto remoto, é preciso localizar o serviço , o que é feito acessando o registro de serviços. Portanto, é necessário que servidores e clientes estejam de acordo com o local (a máquina) onde o registro é realizado. Como resultado dessa tarefa, obtém-se uma referência ao objeto remoto que pode ser utilizada como se fosse uma referência para o objeto local. A utilização desse mecanismo de localizar o serviço através de um diretório ou registro permite que as máquinas clientes ignorem totalmente em que máquinas os serviços solicitados estão operando — uma facilidade conhecida como transparência de localização. Um dos principais objetivos em uma plataforma de objetos distribuídos é atingir transparência de localização, tornando uniforme a forma de utilização de objetos independentemente desses objetos estarem na máquina local da aplicação ou em máquinas distintas. A fim de que se atinja transparência de localização, as seguintes funcionalidades devem ser ofe- recidas:
A primeira funcionalidade, não muito diferente do que ocorre em sistemas com objetos locais, é necessária para que a aplicação conheça as facilidades oferecidas pelo objeto remoto. Referências a objetos também são utilizadas em sistemas com objetos locais, porém com diferen- ças significativas. Em um sistema local, as referências a objetos são tipicamente manipuladores com especificação de endereços de memória. No caso de objetos remotos, esses endereços da memória de outra máquina não têm validade na máquina local. Assim, é preciso oferecer mecanismos que traduzam essas referências entre máquinas de forma transparente para o programador. Para a invocação de métodos de um objeto remoto, além da necessidade de se localizar a refe- rência ao método é preciso oferecer mecanismos para tornar transparente a passagem de argumentos para e o retorno de valores desde o método. Além dessas funcionalidades, a comunicação de falhas no oferecimento da transparência de loca- lização ao programador é essencial. Assim, funcionalidades para comunicar exceções entre máquinas também dever ser suportadas pela plataforma de objetos distribuídos.
Programação orientada a objetos com Java 5.4. Programação com objetos distribuídos
RMI (Remote Method Invocation) é uma das abordagens da tecnologia Java para prover as funci- onalidades de uma plataforma de objetos distribuídos. Esse sistema de objetos distribuídos faz parte do núcleo básico de Java desde a versão JDK 1.1, com sua API sendo especificada através do pacote java.rmi e seus subpacotes. Através da utilização da arquitetura RMI, é possível que um objeto ativo em uma máquina virtual Java possa interagir com objetos de outras máquinas virtuais Java, independentemente da localização dessas máquinas virtuais. A arquitetura RMI oferece a transparência de localização através da organização de três camadas entre os objetos cliente e servidor:
Desenvolvimento da aplicação RMI No desenvolvimento de uma aplicação cliente-servidor usando Java RMI, como para qualquer plataforma de objetos distribuídos, é essencial que seja definida a interface de serviços que serão oferecidos pelo objeto servidor. A especificação de uma interface remota é equivalente à definição de qualquer interface em Java, a não ser pelos seguintes detalhes: a interface deverá, direta ou indiretamente, estender a interface Remote; e todo método da interface deverá declarar que a exceção RemoteException (ou uma de suas superclasses) pode ser gerada na execução do método. Esse exemplo ilustra a definição de uma interface remota para um objeto que contém um contador inteiro:
1 import java.rmi.*; 2 public interface Count extends Remote { 3 void set(int val) throws RemoteException; 4 void reset() throws RemoteException; 5 int get() throws RemoteException; 6 int increment() throws RemoteException; 7 }
Esse contador é manipulado por quatro métodos: set(), para definir um valor inicial para o conta- dor; reset(), para reiniciar o contador com o valor 0; get(), para consultar o valor do contador sem alterá-lo; e increment(), que lê o valor atual do contador e incrementa-o. Os serviços especificados pela interface RMI deverão ser implementados através de uma clas- se Java. Nessa implementação dos serviços é preciso indicar que objetos dessa classe poderão ser acessados remotamente.
Programação orientada a objetos com Java 5.4. Programação com objetos distribuídos
RMI, uma classe que crie o objeto que implementa o serviço e cadastre esse serviço na plataforma de objetos distribuídos. Um objeto servidor RMI simples deve realizar as seguintes tarefas: criar uma instância do objeto que implementa o serviço; e disponibilizar o serviço através do mecanismo de registro. O desenvolvimento de um cliente RMI requer essencialmente a obtenção de uma referência remo- ta para o objeto que implementa o serviço, o que ocorre através do cadastro realizado pelo servidor. Uma vez obtida essa referência, a operação com o objeto remoto é indistingüível da operação com um objeto local.
Usando o serviço de nomes
O aplicativo rmiregistry faz parte da distribuição básica de Java. Tipicamente, esse aplica- tivo é executado como um processo de fundo (em background ) que fica aguardando solicitações em uma porta, que pode ser especificada como argumento na linha de comando. Se nenhum argumento for especificado, a porta 1099 é usada como padrão. O aplicativo rmiregistry é uma implementação de um serviço de nomes para RMI. O serviço de nomes é uma espécie de diretório, onde cada serviço disponibilizado na plataforma é registrado através de um nome do serviço, uma string única para cada objeto que implementa serviços em RMI. Para ter acesso ao serviço de nomes a partir de uma classe Java, são oferecidos dois mecanismos básicos. O primeiro utiliza a classe Naming, do pacote java.rmi. O segundo mecanismo utiliza as facilidades oferecidas através das classes no pacote java.rmi.registry. A classe Naming permite a realização da busca de um serviço pelo nome (lookup) usando o método estático lookup(String nome), que retorna uma referência para o objeto remoto. O serviço de registro aonde a busca se realiza é especificado pela string usando uma sintaxe similar à URL:
rmi://objreg.host:port/objname O protocolo padrão é rmi, sendo no momento o único suportado através desse método. Se não especificado, o host é a máquina local e a porta é 1099. O nome de registro do objeto é a única parte obrigatória desse argumento. Além de lookup() os métodos bind(), rebind(), unbind() e list(), descritos na seqüência, são também suportados. Outra alternativa para ter acesso ao serviço de nomes a partir da aplicação Java é utilizar as funcionalidades do pacote java.rmi.registry, que oferece uma classe e uma interface para que classes Java tenham acesso ao serviço de nomes RMI. A interface Registry representa uma interface para o registro de objetos RMI operando em uma máquina específica. Através de um objeto dessa classe, é possível invocar o método bind() que associa um nome de serviço (um String) ao objeto que o implementa. Para obter uma referência para um objeto Registry são utilizados os métodos da classe Lo- cateRegistry, todos estáticos, tais como getRegistry(). Há quatro versões básicas desse método:
Programação orientada a objetos com Java 5.4. Programação com objetos distribuídos
O método estático createRegistry(int port) pode ser utilizado para iniciar um servi- ço de registro na máquina virtual Java corrente na porta especificada como argumento, retornando também um objeto da classe Registry. Inicialmente, é preciso obter uma referência para o serviço de registro, através da invocação do método:
Registry r = LocateRegistry.getRegistry();
Observe que a referência para Registry é em si uma referência para um objeto remoto, uma vez que a interface Registry é uma extensão da interface Remote. Uma vez que a referência para o serviço de registro tenha sido obtida, é possível acessar as funcionalidades desse serviço através dos métodos da interface Registry. Particularmente, para registrar um novo serviço utiliza-se o método bind():
r.bind(serviceName, myCount);
O objeto que está sendo registrado deve implementar também a interface Remote, que identifica todos os objetos que podem ser acesados remotamente. Outros serviços disponíveis através dos métodos de Registry incluem atualização, remoção e busca dos serviços lá registrados. Para atualizar um registro já existente, o método rebind() pode ser utilizado. Para eliminar um registro, utiliza-se o método unbind(). Dado o nome de um serviço, o objeto Remote que o implementa pode ser obtido pelo método lookup(). O método list() retorna um arranjo de String com os nomes de todos os serviços registrados.
Implementação do servidor RMI Como observado, um objeto servidor RMI simples deve realizar as seguintes tarefas:
Esse exemplo de servidor RMI para o contador remoto cria uma instância da implementação do serviço e coloca-a à disposição de potenciais clientes, registrando-o no registry RMI:
1 import java.rmi.registry.*; 2 public class CountServer { 3 public static void main(String[] args) { 4 try { 5 String serviceName = "Count001"; 6 CountImpl myCount = new CountImpl(); 7 Registry r = LocateRegistry.getRegistry();