API Java do SCS
Tecgraf PUC-Rio
Setembro de 2013
A API do SCS
• A API fica encapsulada em uma classe
chamada ComponentBuilder, utilizada para
“montar” um componente
• Definindo suas facetas, receptáculos e
ComponentId
• Um componente SCS-Java é representado
por uma interface Java ComponentContext
• Existem classes auxiliares
Criação de um Componente
• São necessários alguns passos:
1. Alterar facetas básicas (opcional)
2. Implementar suas facetas (opcional)
3. Criar o ComponentId
4. Instanciar a representação local do
componente
5. Adicionar facetas (opcional)
6. Adicionar receptáculos (opcional)
Criação de um Componente
• Outra opção é utilizar descritores XML
• Externalizam como deve ser a construção do
componente
• Não é necessário recompilar o código para mudar a
configuração do componente
• Os passos passam a ser:
• Descrever o componente em um arquivo XML
• Implementar suas facetas (opcional)
• Utilizar a API para construir o componente a partir
do arquivo XML
Implementação de uma
Faceta
Criação de Facetas
• Uma faceta SCS nada mais é do que uma
implementação de uma interface CORBA
• O SCS adiciona algumas convenções, mas a
implementação da interface se dá da mesma
forma
• Por herança ou delegação
public class MyFacetServant extends MyFacetPOA {
}
Criação de Facetas
• Pode ser útil também ter um construtor que
receba a representação local do componente ao
qual essa faceta pertencerá
• Assim pode-se ter acesso a outras facetas e
dados comuns ao componente como um todo
• Essa representação local é chamada de contexto
do componente (classe ComponentContext)
• Não é obrigatório, a não ser na construção por
XML
Criação de Facetas
• Método _get_component()
– Inicialmente criado para o CCM e CORBA 3.0
– Presente na especificação de CORBA 2.3.x
• Suportado em Java pelo JacORB mas não pelo ORB da
Sun
– Fornece a interface mais básica de um componente,
a partir de qualquer outra de suas interfaces. Isso
geralmente permite obter uma interface que acesse
outras interfaces
• No SCS, a interface mais básica é a IComponent, da qual
pode-se obter as outras facetas do componente
Criação de Facetas
• Definição do método _get_component()
– Basta retornar o resultado do método auxiliar getIComponent
existente na interface ComponentContext
//@Override
public org.omg.CORBA.Object _get_component() {
return context.getIComponent();
}
– Opcional, mas uma mensagem de aviso será impressa caso o
método não seja implementado
– Possibilidade do método ser adicionado automaticamente no
futuro
• Desistimos da idéia por enquanto pois estamos investigando outras
soluções para versões futuras do SCS
Criação de Facetas
• Exemplo de faceta completa
public class MyFacetServant extends MyFacetPOA {
private ComponentContext context;
public MyFacetServant(ComponentContext context) {
this.context = context;
}
//@Override
public org.omg.CORBA.Object _get_component() {
return context.getIComponent();
}
...
}
Representação Local do
Componente
(ComponentContext)
Criação do ComponentId
• Definição do ComponentId
• Idêntico ao demonstrado na IDL
ComponentId cpId = new ComponentId(
“MyComponentName”,
(byte) 1, (byte) 0, (byte) 0,
“windows”
);
O Componente Java
• ComponentContext
– Atua como um envólucro que facilita o uso do
componente como uma entidade única e não
apenas um aglomerado de facetas e receptáculos
• Representação local do componente
• Acesso a todas as facetas (incluindo as básicas) e
receptáculos
• Guarda os metadados, como descrições de facetas e
receptáculos e identificador do componente
(ComponentId)
O Componente Java
• ComponentContext
– A classe pode ser estendida para adicionar outros
dados de uso global no componente
• Dados acessados por mais de uma faceta
• Dados referentes ao componente em si, não a uma
faceta específica
• Métodos
Classe Java ComponentContext
• public ComponentContext(ORB orb, POA poa,
ComponentId id)
– Construtor que recebe o ORB e POA a serem utilizados nas facetas
do componente e o ComponentId
– Adiciona automaticamente as facetas básicas (já ativadas no POA
fornecido)
• public ComponentId getComponentId()
– Retorna o ComponentId fornecido no construtor
Classe Java ComponentContext
• public void addFacet(String name, String
interfaceName, Servant servant)
– Adiciona uma faceta ao componente
– Ativa o objeto CORBA no POA
• public void removeFacet(String name)
– Remove uma faceta do componente
– Desativa o objeto CORBA no POA
• public void updateFacet(String name, Servant
servant)
– Desativa o objeto CORBA da faceta no POA
– Substitui o objeto CORBA pelo novo fornecido
– Ativa o novo objeto CORBA no POA
Classe Java ComponentContext
• public void addReceptacle(String name,
String interfaceName, boolean isMultiplex)
– Adiciona um receptáculo ao componente
• public void removeReceptacle(String name)
– Remove um receptáculo do componente
Classe Java ComponentContext
• public Collection<Facet> getFacets()
– Retorna uma coleção com todas as facetas do componente
– A classe Facet contém o objeto CORBA e os metadados associados
• public Facet getFacetByName(String name)
– Retorna uma faceta específica
• public Collection<Receptacle>
getReceptacles()
– Retorna uma coleção com todos os receptáculos do componente
• public Receptacle getReceptacleByName(String
name)
– Retorna um receptáculo específico
Classe Java ComponentContext
• public IComponent getIComponent()
– Retorna a faceta IComponent do componente
• public String getComponentIdAsString()
– Retorna as informações do ComponentId em uma string
• public POA getPOA()
– Retorna o POA fornecido no construtor e utilizado na ativação dos
objetos CORBA do componente
• public ORB getORB()
– Retorna o ORB fornecido no construtor
Exemplos
• Como obter uma faceta a partir de outra?
context.getFacetByName(“FacetName”).getServant()
• Como acessar uma faceta externa conectada a um
receptáculo?
context.getReceptacleByName(“ReceptacleName”).get
Connections()
Alteração de Facetas Básicas
• Novas implementações podem ser fornecidas
para as facetas básicas
• A implementação é feita normalmente como
em qualquer faceta / objeto CORBA, basta
seguir a interface desejada
• Após criar o ComponentContext, deve-se
substituir o servant da faceta desejada pelo
novo (método updateFacet)
Outras Funcionalidades
XMLComponentBuilder
• É possível montar um componente a partir de um arquivo
descritor em XML
‒ Substitui os passos demonstrados anteriormente
• O descritor deve conter no mínimo:
‒ Identificador do componente
• Pode-se fornecer, opcionalmente:
‒ Descrições de facetas (nome, interface, e classe a ser instanciada)
• A classe da faceta deve conter um construtor que receba apenas
um ComponentContext como parâmetro
‒ Descrições de receptáculos (nome, interface, multiplex)
‒ Classe a ser usada como ComponentContext
XMLComponentBuilder
• Exemplo de arquivo XML
<?xml version="1.0" encoding="iso-8859-1" ?>
<scs:component xmlns:scs="tecgraf.scs.core">
<id>
<name>MyComponent</name>
<version>1.0.0</version>
<platformSpec>Java 1.6</platformSpec>
</id>
<facets>
<facet>
<name>MyFacet</name>
<interfaceName>IDL:module/Interface:1.0</interfaceName>
<facetImpl>mypackage.InterfaceImpl</facetImpl>
</facet>
<facet>
<name>AnotherFacet</name>
<interfaceName>IDL:module/AnotherInterface:1.0</interfaceName>
<facetImpl>mypackage.AnotherInterfaceImpl</facetImpl>
</facet>
</facets>
</scs:component>
XMLComponentBuilder
• Exemplo de uso da API
…
ORB orb = ORB.init(args, orbProps);
POA poa = POAHelper.narrow(orb.resolve_initial_references("RootPOA"));
poa.the_POAManager().activate();
XMLComponentBuilder xmlBuilder = new XMLComponentBuilder(orb, poa);
File is = new File("resources/" + args[0]);
ComponentContext context;
try {
context = xmlBuilder.build(is);
}
catch (SCSException e) {
e.getCause().printStackTrace();
return;
}
…
Aplicação Exemplo
Exemplo passo-a-passo
• Veremos um exemplo, passo-a-passo, de
desenvolvimento de uma aplicação SCS
usando Java
• Para desenvolver a aplicação, usaremos o
JacORB como ORB tanto para o cliente
quanto para o servidor, e as bibliotecas do
SCS
Exemplo de Aplicação
ExchangePrinter
StockSeller
StockServer
StockLogger
Stock
Exchange
• O componente StockSeller implementa duas facetas: StockServer e StockExchange
• O componente StockSeller tem um receptáculo para componentes que implementem
a faceta ExchangePrinter
• O componente StockLogger implementa a faceta ExchangePrinter
Passo 1: Alterando a IDL
// StockMarket.idl
// O módulo StockMarket consiste das definições
// úteis para desenvolvimento de aplicações
// que lidam com mercado de ações.
module StockMarket {
...
// A interface ExchangePrinter é a interface que
// representa uma impressora de negociações de ações.
interface ExchangePrinter {
// Imprime que houve uma negociação da ação indicada.
// A saída utilizada para impressão não é especificada.
// Exemplos de saídas: tela, arquivo, clients remotos.
void print(in StockSymbol symbol);
};
// A interface StockExchange é a interface que permite
// a compra de ações.
interface StockExchange {
// Usa os componentes ExchangePrinter que estejam
// conectados para imprimir a negociaçao efetuada.
boolean buyStock(in StockSymbol symbol);
};};
Passo 2: Implementando as facetas
• Facetas são interfaces CORBA e, portanto,
sua implementação segue as mesmas regras
que vimos nos exemplos de CORBA
• Precisaremos alterar a classe
StockServerImpl para que ela se torne uma
Faceta SCS
• Além disso, precisaremos implementar as
facetas StockExchange e ExchangePrinter
StockServerImpl
/**
* StockServerImpl implementa a interface IDL StockServer
*/
public class StockServerImpl extends StockServerPOA {
/**
* Construtor
* @param context o contexto do componente dono da faceta.
*/
public StockServerImpl(ComponentContext context) { }
/**
* Retorna o valor corrente a determinada ação do mercado, dado o
* símbolo que a representa.
*/
@Override
public float getStockValue(String symbol) { }
/**
* Retorna a sequência com todos os símbolos que definem as ações
* de mercado mantidas por esse StockServer.
*/
@Override
public String[] getStockSymbols() { }
}
/**
* Obtém a faceta IComponent do componente.
* @return a faceta IComponent
*/
public org.omg.CORBA.Object _get_component() {
}
StockExchangeImpl
/**
* StockExchangeImpl implementa a interface IDL StockExchange
*/
public class StockExchangeImpl extends StockExchangePOA {
/**
* Construtor
*
* @param context o contexto do componente dono da faceta.
*/
public StockExchangeImpl(ComponentContext context) { }
/**
* Quando uma ação é negociada, seu valor aumenta em uma taxa de 10%.
* Usa os componentes StockLogger que estejam conectados para imprimir
* a negociaçao efetuada.
*/
@Override
public boolean buyStock(String symbol) { }
}
/**
* Obtém a faceta IComponent do componente.
*
* @return a faceta Icomponent
*/
public org.omg.CORBA.Object _get_component() {
}
DisplayExchangePrinter
/**
* DisplayExchangePrinterImpl implementa a interface IDL ExchangePrinter.
* Essa implementação usa o display (console) para mostrar a negociação de
* cada ação do mercado.
*/
public class DisplayExchangePrinterImpl extends ExchangePrinterPOA {
/**
* Construtor
*
* @param context o contexto do componente dono da faceta.
*/
public DisplayExchangePrinterImpl(ComponentContext context) {
}
/**
* Imprime que houve uma negociação da ação indicada. A saída utilizada
* para impressão não é especificada. Exemplos de saídas: tela, arquivo,
* clients remotos.
*/
@Override
public void print(String text) { }
}
/**
* Obtém a faceta IComponent do componente.
*
* @return a faceta Icomponent
*/
public org.omg.CORBA.Object _get_component() {
}
Passo 3: Criando o componente StockSeller
• O componente StockSeller oferece as facetas
StockServer e StockExchange
• O componente StockSeller possui um
receptáculo para conectar um ou mais
compontes que implementem a faceta
ExchangePrinter
Inicia o ORB e ativa o POA
/*
* As propriedades que informam o uso do JacORB como ORB.
*/
Properties orbProps = new Properties();
orbProps.setProperty("org.omg.CORBA.ORBClass", "org.jacorb.orb.ORB");
orbProps.setProperty("org.omg.CORBA.ORBSingletonClass", "org.jacorb.orb.ORBSingl
/* Inicializa o ORB */
ORB orb = ORB.init(args, orbProps);
/* Obtém a referência para o POA e inicializa o POA */
POA poa = POAHelper.narrow(orb.resolve_initial_references("RootPOA"));
poa.the_POAManager().activate();
...
orb.run();
• A inicialização do ORB e ativação do POA, ao
iniciar o servidor, são iguais ao que já usamos nos
exemplos anteriores.
• O servidor deve, após criar o componente, deixar o
ORB aguardando as requisições
Criando o identificador do componente
ComponentId componentId = new ComponentId(
"StockSeller", (byte) 1, (byte) 0, (byte) 0, "Java");
• Todo componente precisa ter um identificador, que é
descrito usando a classe ComponentId
Criando o componente
ComponentContext context = new Component(orb, poa, componentId);
• A classe ComponentContext deve ser instanciada
para servir como representação local do componente
(ou uma classe mais específica definida pelo usuário)
• Esse componente já conterá as facetas básicas do SCS
Criando e adicionando as facetas
// cria as facetas
StockServerImpl stockServer = new StockServerImpl(context);
StockExchangeImpl stockExchange = new StockExchangeImpl(context);
// adiciona as facetas ao componente
context.addFacet("StockServer", StockServerHelper.id(), stockServer);
context.addFacet("StockExchange", StockExchangeHelper.id(), stockExchange);
Adicionando receptáculos
// adiciona o receptáculo
context.addReceptacle("ExchangePrinter", ExchangePrinterHelper.id(), true);
Salva o IOR em um arquivo
Icomponent component = context.getIComponent();
PrintWriter ps = new PrintWriter(new FileOutputStream(new File(args[0])));
ps.println(orb.object_to_string(component));
ps.close();
• Nessa solução, ainda usaremos um arquivo para gravar
a referência para o objeto CORBA
• Note que estamos usando a referência para um
IComponent
Passo 4: Criando o componente StockLogger
• O componente StockLogger oferece a faceta
ExchangePrinter
• O código StockLoggerMain.java é responsável
por criar o componente SCS StockLogger
• Em nosso exemplo, o código que o conecta ao
componente StockSeller é uma aplicação
separada
• A criação do componente StockLogger é similar
ao que fizemos para criar o StockSeller, exceto
que não há receptáculos
Passo 5: Recuperando as referências dos
componentes para conectá-los
/*
* Lê o IOR do componente StockSeller do arquivo seller.ior
*/
BufferedReader reader = new BufferedReader(new InputStreamReader(
new FileInputStream(args[0])));
String ior_seller = reader.readLine();
reader.close();
/*
* Lê o IOR do componente StockLogger do arquivo logger.ior
* parâmetro 2.
*/
reader = new BufferedReader(new InputStreamReader(
new FileInputStream(args[1])));
String ior_logger = reader.readLine();
reader.close();
• A conexão pode ser feita por um dos componentes do
sistema ou por um cliente externo
Obtendo as facetas IReceptacles do
StockSeller e ExchangePrinter do StockLogger
/* Obtém a referência para o componente StockSeller. */
org.omg.CORBA.Object obj = orb.string_to_object(ior_seller);
IComponent stockSeller = IComponentHelper.narrow(obj);
/* Obtém a referência para o componente StockLogger. */
obj = orb.string_to_object(ior_logger);
IComponent stockLogger = IComponentHelper.narrow(obj);
/* Obtém a referência para IReceptacles do StockSeller */
IReceptacles irStockSeller = IReceptaclesHelper.narrow(
stockSeller.getFacet(IReceptaclesHelper.id()));
/* Obtém a referência para ExchangePrinter do StockLogger */
ExchangePrinter printer = ExchangePrinterHelper.narrow(
stockLogger.getFacet(ExchangePrinterHelper.id()));
• Precisaremos da faceta ExchangePrinter do componente
StockLogger, pois é essa faceta que será conectada ao
receptáculo do StockSeller
• A faceta IComponent tem métodos para recuperar suas
outras facetas
Conectando a faceta ExchangePrinter do
StockLogger no receptáculo do StockSeller
/*
* Faz a conexão da faceta ExchangePrinter do componente StockLogger no
* receptáculo do StockSeller.
*/
irStockSeller.connect("ExchangePrinter", printer);
• Usamos a faceta IReceptacles de StockSeller para
fazer a conexão dos componentes
• O método connect faz a conexão do componente
StockLogger usando sua faceta ExchangePrinter
• O exemplo não mostra para simplificar, mas deve-se tratar
as exceções CORBA como no exercício anterior em toda
chamada remota CORBA, assim como exceções específicas
do método
Passo 6: Usando os componentes conectados
ao receptáculo do StockSeller
• A implementação do método buyStock pela
faceta StockExchange do componente
StockSeller deve chamar o método print da
faceta ExchangePrinter conectada a esse
mesmo componte
Obtendo o receptáculo correspondente a
ExchangePrinter
public boolean buyStock(String symbol) {
…
Receptacle receptacle = context.getReceptacleByName("ExchangePrinter");
if (receptacle == null) {
…
}
List<ConnectionDescription> connections = receptacle.getConnections();
for (ConnectionDescription connection : connections) {
try {
ExchangePrinter printer = ExchangePrinterHelper.narrow(connection.objref);
printer.print("Ação " + symbol + " foi negociada");
}
catch(...) {...}
}
...
}
• O contexto do componente possui o método getReceptacleByName que
retorna um receptáculo do componente
• A classe Receptacle permite então recuperar as conexões
• As descrições das conexões são recuperadas com o método
getConnections de Receptacle
• O campo objref de ConnectionDescription possui a referência
para a faceta do componente conectado
Passo 7: Usando o componente StockSeller
• O cliente usa o componente StockSeller
através de suas facetas
• O StockMarketClient.java possui a etapa
de inicialização do ORB que já vimos nos
exemplos anteriores
• O que muda é o uso das facetas do
componente para invocar os métodos
remotos
Obtendo a referência para o componente
StockSeller
/*
* Lê o IOR do componente StockSeller do arquivo seller.ior
* parâmetro.
*/
BufferedReader reader = new BufferedReader(new InputStreamReader(
new FileInputStream(args[0])));
String ior_seller = reader.readLine();
reader.close();
/* Obtém a referência para component StockSeller. */
org.omg.CORBA.Object ior = orb.string_to_object(ior_seller);
IComponent stockSeller = IComponentHelper.narrow(ior);
• O cliente recupera a referência para o componente
StockSeller lendo do arquivo recebido por parâmetro
Obtendo as facetas StockServer e
StockExchange do componente StockSeller
try {
/* Obtém a faceta StockServer */
org.omg.CORBA.Object obj = stockSeller.getFacetByName("StockServer");
StockServer stockServerFacet = StockServerHelper.narrow(obj);
/* Obtém a faceta StockExchange */
obj = stockSeller.getFacetByName("StockExchange");
StockExchange stockExchangeFacet = StockExchangeHelper.narrow(obj);
}
catch (…) {
…
}
• Tendo o componente, as facetas StockServer e
StockExchange são recuperadas, pelo nome ou pela
interface
Invocando os métodos disponibilizados em
cada faceta
try {
/* Obtém os símbolos de todas as ações. */
String[] stockSymbols = stockServerFacet.getStockSymbols();
/* Mostra as ações com seus respectivos valores */
for (int i = 0; i < stockSymbols.length; i++) {
System.out.println(stockSymbols[i] + " " +
stockServerFacet.getStockValue(stockSymbols[i]));
}
if (stockSymbols.length > 0) {
String first = stockSymbols[0];
System.out.println("--Compra a ação :" + first);
boolean success = stockExchangeFacet.buyStock(first);
if (success) {
System.out.println("--Ação " + first + " depois da negociação: " +
stockServerFacet.getStockValue(first));
}
else {
System.out.println("--Não foi possível negociar a ação " + first);
}
}
catch (…) {…}
• O cliente faz as chamadas aos métodos usando as
respectivas facetas
Download

Slide 1 - Tecgraf JIRA / Confluence - PUC-Rio