SCS Java - Tecgraf JIRA / Confluence - PUC-Rio

Propaganda
API Java do SCS
Tecgraf PUC-Rio
Fevereiro de 2014
Versão 3 – fevereiro/2014
A API do SCS
• A API da biblioteca SCS permite a construção de
componentes
– Manualmente
– Através de descritores
• A API lida apenas com a representação local do
componente
– Encarrega-se apenas da construção
– Não lida com a composição de vários componentes
(que pode ser distribuída)
• A representação local de um componente SCSJava é dada pela classe ComponentContext
Versão 3 – fevereiro/2014
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)
Versão 3 – fevereiro/2014
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
Versão 3 – fevereiro/2014
Implementação de uma Faceta
Versão 3 – fevereiro/2014
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 {
}
Versão 3 – fevereiro/2014
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)
• Esse construtor não é obrigatório, a não ser
na construção por XML
Versão 3 – fevereiro/2014
Criação de Facetas
• Exemplo de faceta completa
public class MyFacetServant extends MyFacetPOA {
private ComponentContext context;
public MyFacetServant(ComponentContext context) {
this.context = context;
}
...
}
Versão 3 – fevereiro/2014
Representação Local do Componente
(ComponentContext)
Versão 3 – fevereiro/2014
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,
“java6”
);
Versão 3 – fevereiro/2014
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)
Versão 3 – fevereiro/2014
O Componente Java
• ComponentContext – Diferença entre representações
– Visão distribuída de um componente
– Em um ambiente distribuído (CORBA), existe apenas o que está no
contrato da IDL (scs.idl)
– O componente é essencialmente o conjunto das facetas IComponent,
IReceptacles, IMetaInterface e facetas adicionais
– NÃO existe uma “caixa” que agrupe essas facetas em um bloco,
representando o componente como um todo
– A faceta IComponent é o que mais se aproxima de representar o
componente
– Receptáculos não existem de fato, e são manuseados apenas através da
faceta IReceptacles
– Visão local de um componente
– Objeto ComponentContext une as facetas e receptáculos em uma única
representação
Versão 3 – fevereiro/2014
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
Versão 3 – fevereiro/2014
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
Versão 3 – fevereiro/2014
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
Versão 3 – fevereiro/2014
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
Versão 3 – fevereiro/2014
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
Versão 3 – fevereiro/2014
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
Versão 3 – fevereiro/2014
Exemplos
• Como obter uma faceta a partir de outra?
context.getFacetByName(“FacetName”).getServant()
• Como acessar uma dependência conectada a um
receptáculo?
context.getReceptacleByName(“ReceptacleName”).get
Connections()
Versão 3 – fevereiro/2014
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)
Versão 3 – fevereiro/2014
Alteração de Facetas Básicas
ComponentId cpId = new ComponentId(
“MyComponentName”,
(byte) 1, (byte) 0, (byte) 0,
“java6”
);
ComponentContext context = new ComponentContext(orb, poa,
cpId);
MyIComponentClass myIC = new MyIComponentClass(context);
context.updateFacet(“IComponent”, myIC);
Versão 3 – fevereiro/2014
Outras Funcionalidades
Versão 3 – fevereiro/2014
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
• A biblioteca fornece um arquivo xsd com o formato
Versão 3 – fevereiro/2014
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>java6</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>
Versão 3 – fevereiro/2014
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;
}
…
Versão 3 – fevereiro/2014
Aplicação Exemplo
Versão 3 – fevereiro/2014
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
Versão 3 – fevereiro/2014
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
Versão 3 – fevereiro/2014
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);
};};
Versão 3 – fevereiro/2014
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
Versão 3 – fevereiro/2014
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) throws UnknownSymbol { }
/**
* Retorna a sequência com todos os símbolos que definem as ações
* de mercado mantidas por esse StockServer.
*/
@Override
public String[] getStockSymbols() { }
Versão 3 – fevereiro/2014
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) { }
}
Versão 3 – fevereiro/2014
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,
* clientes remotos.
*/
@Override
public void print(String text) { }
}
Versão 3 – fevereiro/2014
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
Versão 3 – fevereiro/2014
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.ORBSingleton");
/* 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
Versão 3 – fevereiro/2014
Criando o identificador do componente
ComponentId componentId = new ComponentId(
"StockSeller", (byte) 1, (byte) 0, (byte) 0, “java6");
• Todo componente precisa ter um identificador, que é
descrito usando a classe ComponentId
Versão 3 – fevereiro/2014
Criando o componente
ComponentContext context = new ComponentContext(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
Versão 3 – fevereiro/2014
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);
Versão 3 – fevereiro/2014
Adicionando receptáculos
// adiciona o receptáculo
context.addReceptacle("ExchangePrinter", ExchangePrinterHelper.id(), true);
Versão 3 – fevereiro/2014
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
Versão 3 – fevereiro/2014
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
Versão 3 – fevereiro/2014
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
Versão 3 – fevereiro/2014
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
Versão 3 – fevereiro/2014
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
Versão 3 – fevereiro/2014
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 componente
Versão 3 – fevereiro/2014
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
• A classe Receptacle permite então recuperar as descrições das 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 IComponent da dependência conectada
Versão 3 – fevereiro/2014
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
Versão 3 – fevereiro/2014
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
Versão 3 – fevereiro/2014
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
Versão 3 – fevereiro/2014
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
Versão 3 – fevereiro/2014
Download