API C do SCS Tecgraf PUCRio Novembro de
API C# do SCS Tecgraf PUC-Rio Novembro de 2013 versão 1 - julho/2013
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 composição de vários componentes (que pode ser distribuída) • A representação local de um componente SCS-C# é dada pela interface Component. Context versão 1 - julho/2013
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 Component. Id 4. Instanciar a representação local do componente 5. Adicionar facetas (opcional) 6. Adicionar receptáculos (opcional) versão 1 - julho/2013
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 1 - julho/2013
Implementação de uma Faceta versão 1 - julho/2013
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 public class My. Facet. Servant : Marshal. By. Ref. Object, My. Facet { } versão 1 - julho/2013
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 (interface Component. Context) • Esse construtor não é obrigatório, a não ser na construção por XML versão 1 - julho/2013
Criação de Facetas • Exemplo de faceta completa public class My. Facet. Servant : Marshal. By. Ref. Object, My. Facet { private Component. Context _context; public My. Facet. Servant(Component. Context context) { _context = context; }. . . } versão 1 - julho/2013
Representação Local do Componente (Component. Context) versão 1 - julho/2013
Criação do Component. Id • Definição do Component. Id • Idêntico ao demonstrado na IDL Component. Id cp. Id = new Component. Id( “My. Component. Name”, 1, 0, 0, “. NET 4. 0” ); versão 1 - julho/2013
O Componente C# • Component. Context – 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 (Component. Id) • Implementação padrão dada pela classe Default. Component. Context versão 1 - julho/2013
O Componente C# • Component. Context – 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, IMeta. Interface 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 Component. Context une as facetas e receptáculos em uma única representação versão 1 - julho/2013
O Componente C# • Component. Context – A classe Default. Component. Context 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 1 - julho/2013
Interface C# Component. Context • public (Default)Component. Context(Component. Id id) – Construtor que recebe o Component. Id – Adiciona automaticamente as facetas básicas (e já as ativa no ORB) • Component. Id Get. Component. Id() – Retorna o Component. Id fornecido no construtor • IComponent Get. IComponent() – Retorna o objeto CORBA referente à faceta IComponent do componente versão 1 - julho/2013
Interface C# Component. Context • void Add. Facet(String name, String interface. Name, Marshal. By. Ref. Object servant) – Adiciona uma faceta ao componente – Ativa o objeto CORBA no ORB • void Remove. Facet(String name) – Remove uma faceta do componente – Desativa o objeto CORBA no ORB • void Update. Facet(String name, Marshal. By. Ref. Object servant) – Desativa o objeto CORBA da faceta no ORB – Substitui o objeto CORBA pelo novo fornecido – Ativa o novo objeto CORBA no ORB versão 1 - julho/2013
Interface C# Component. Context • void Add. Receptacle(String name, String interface. Name, Boolean is. Multiple) – Adiciona um receptáculo ao componente • void Remove. Receptacle(String name) – Remove um receptáculo do componente versão 1 - julho/2013
Interface C# Component. Context • IDictionary<String, Facet> Get. Facets() – Retorna um dicionário com todas as facetas do componente, associadas aos seus nomes – A classe Facet contém o objeto CORBA e os metadados associados • Facet Get. Facet. By. Name(String name) – Retorna uma faceta específica • IDictionary<String, Receptacle> Get. Receptacles() – Retorna um dicionário com todos os receptáculos do componente, associados aos seus nomes • Receptacle Get. Receptacle. By. Name(String name) – Retorna um receptáculo específico versão 1 - julho/2013
Exemplos • Como obter uma faceta a partir de outra? context. Get. Facet. By. Name(“Facet. Name”). Reference • Como acessar uma dependência conectada a um receptáculo? context. Get. Receptacle. By. Name(“Receptacle. Name”). Get Connections() versão 1 - julho/2013
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 Component. Context, deve-se substituir o servant da faceta desejada pelo novo (método update. Facet) versão 1 - julho/2013
Alteração de Facetas Básicas Component. Id cp. Id = new Component. Id( “My. Component. Name”, (byte) 1, (byte) 0, “windows” ); Component. Context context = new Default. Component. Context(cp. Id); My. IComponent. Class my. IC = new My. IComponent. Class(context); context. Update. Facet(“IComponent”, my. IC); versão 1 - julho/2013
Outras Funcionalidades versão 1 - julho/2013
XMLComponent. Builder • É 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 Component. Context como parâmetro ‒ Descrições de receptáculos (nome, interface, multiplex) ‒ Classe a ser usada como Component. Context • A biblioteca fornece um arquivo xsd com o formato versão 1 - julho/2013
XMLComponent. Builder • Exemplo de arquivo XML <? xml version="1. 0" encoding="iso-8859 -1" ? > <scs: component xmlns: scs="tecgraf. scs. core"> <id> <name>My. Component</name> <version>1. 0. 0</version> <platform. Spec>. NET 4. 0</platform. Spec> </id> <facets> <facet> <name>My. Facet</name> <interface. Name>IDL: module/Interface: 1. 0</interface. Name> <facet. Impl>mypackage. Interface. Impl</facet. Impl> </facet> <name>Another. Facet</name> <interface. Name>IDL: module/Another. Interface: 1. 0</interface. Name> <facet. Impl>mypackage. Another. Interface. Impl</facet. Impl> </facets> </scs: component> versão 1 - julho/2013
XMLComponent. Builder • Exemplo de uso da API … Xml. Text. Reader reader = new Xml. Text. Reader(args[0]); Xml. Component. Builder xml. Builder = new Xml. Component. Builder(reader); Component. Context context = xml. Builder. build(); … versão 1 - julho/2013
Aplicação Exemplo versão 1 - julho/2013
Exemplo passo-a-passo • Veremos um exemplo, passo-a-passo, de desenvolvimento de uma aplicação SCS usando C# • Para desenvolver a aplicação, usaremos o IIOP. NET como ORB tanto para o cliente quanto para o servidor, e as bibliotecas do SCS versão 1 - julho/2013
Exemplo de Aplicação Stock. Seller Stock. Server Exchange. Printer Stock. Logger Stock Exchange • O componente Stock. Seller implementa duas facetas: Stock. Server e Stock. Exchange • O componente Stock. Seller tem um receptáculo para componentes que implementem a faceta Exchange. Printer • O componente Stock. Logger implementa a faceta Exchange. Printer versão 1 - julho/2013
Passo 1: Alterando a IDL // Stock. Market. idl // O módulo Stock. Market consiste das definições // úteis para desenvolvimento de aplicações // que lidam com mercado de ações. module Stock. Market {. . . // A interface Exchange. Printer é a interface que // representa uma impressora de negociações de ações. interface Exchange. Printer { // 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 Stock. Symbol symbol); }; // A interface Stock. Exchange é a interface que permite // a compra de ações. interface Stock. Exchange { // Usa os componentes Exchange. Printer que estejam // conectados para imprimir a negociaçao efetuada. boolean buy. Stock(in Stock. Symbol symbol); }; }; versão 1 - julho/2013
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 Stock. Server. Impl para que ela se torne uma Faceta SCS • Além disso, precisaremos implementar as facetas Stock. Exchange e Exchange. Printer versão 1 - julho/2013
Stock. Server. Impl namespace Stock. Seller { public class Stock. Server. Impl : Marshal. By. Ref. Object, Stock. Server { public Stock. Server. Impl(Stock. Seller. Context context) { } /// <summary> /// Retorna o valor corrente de uma ação específica. /// </summary> /// <param name="symbol">Símbolo identificador da ação. </param> /// <returns>O valor da ação requisitada. </returns> public float get. Stock. Value(string symbol) { } /// <summary> /// Retorna os símbolos de todas as ações disponíveis. /// </summary> /// <returns>As ações disponíveis. </returns> public string[] get. Stock. Symbols() { } public override object Initialize. Lifetime. Service() { } } } versão 1 - julho/2013
Stock. Exchange. Impl namespace Stock. Seller { public class Stock. Exchange. Impl : Marshal. By. Ref. Object, Stock. Exchange { public Stock. Exchange. Impl(Stock. Seller. Context context) { _context = context; } /// <summary> /// Realiza a compra de uma ação. Quando uma ação é negociada, seu valor /// aumenta em uma taxa de 10%. /// Usa os componentes Exchange. Printer que estejam /// conectados para imprimir a negociaçao efetuada. /// </summary> /// <param name="symbol">Símbolo da ação a ser comprada. </param> /// <returns>True se a venda da ação foi bem sucedida, False caso contrário. /// </returns> public bool buy. Stock(string symbol) { } public override object Initialize. Lifetime. Service() { } } } versão 1 - julho/2013
Display. Exchange. Printer namespace Stock. Logger { public class Display. Exchange. Printer : Marshal. By. Ref. Object, Exchange. Printer { public Display. Exchange. Printer(Component. Context context) { } /// <summary> /// Imprime que houve uma negociação da ação indicada. /// A saída utilizada para impressão é a tela. /// </summary> /// <param name="text">Texto a ser impresso na tela. </param> public void print(string text) { } public override object Initialize. Lifetime. Service() { } } } versão 1 - julho/2013
Passo 3: Criando o componente Stock. Seller • O componente Stock. Seller oferece as facetas Stock. Server e Stock. Exchange • O componente Stock. Seller possui um receptáculo para conectar um ou mais compontes que implementem a faceta Exchange. Printer versão 1 - julho/2013
Inicia o ORB // inicializa o ORB, indicando que utilize uma porta aleatória para // receber chamadas Iiop. Channel chan = new Iiop. Channel(0); Channel. Services. Register. Channel(chan, false); . . . Thread. Sleep(Timeout. Infinite); • A inicialização do ORB, ao iniciar o servidor, é igual à que já usamos nos exemplos anteriores. • O servidor deve, após criar o componente, deixar ao menos uma thread ativa para que o ORB possa ficar aguardando as requisições versão 1 - julho/2013
Criando o identificador do componente Component. Id component. Id = new Component. Id( "Stock. Seller", 1, 0, 0, “. NET 4. 0"); • Todo componente precisa ter um identificador, que é descrito usando a classe Component. Id versão 1 - julho/2013
Criando o componente Component. Context context = new Default. Component. Context(component. Id); • A classe Default. Component. Context 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 1 - julho/2013
Criando e adicionando as facetas // cria as facetas Stock. Server. Impl stock. Server = new Stock. Server. Impl(context); Stock. Exchange. Impl stock. Exchange = new Stock. Exchange. Impl(context); // adiciona as facetas ao componente string server. Type = Repository. Get. Repository. ID(typeof (Stock. Server)); string exchange. Type = Repository. Get. Repository. ID(typeof (Stock. Exchange)); context. Add. Facet("Stock. Server", server. Type, stock. Server); context. Add. Facet("Stock. Exchange", exchange. Type, stock. Exchange); versão 1 - julho/2013
Adicionando receptáculos // adiciona o receptáculo string printer. Type = Repository. Get. Repository. ID(typeof (Exchange. Printer)); context. Add. Receptacle("Exchange. Printer", printer. Type, true); versão 1 - julho/2013
Salva o IOR em um arquivo Orb. Services orb = Orb. Services. Get. Singleton(); string ior = orb. object_to_string(context. Get. IComponent()); File. Write. All. Text(args[0], ior); • 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 1 - julho/2013
Passo 4: Criando o componente Stock. Logger • O componente Stock. Logger oferece a faceta Exchange. Printer • O código Stock. Logger. Main. cs é responsável por criar o componente SCS Stock. Logger • Em nosso exemplo, o código que o conecta ao componente Stock. Seller é uma aplicação separada • A criação do componente Stock. Logger é similar ao que fizemos para criar o Stock. Seller, exceto que não há receptáculos versão 1 - julho/2013
Passo 5: Recuperando as referências dos componentes para conectá-los // Lê os IORs dos arquivos cujos nomes são passados como parâmetros string seller. IOR = File. Read. All. Text(args[0]); string logger. IOR = File. Read. All. Text(args[1]); • A conexão pode ser feita por um dos componentes do sistema ou por um cliente externo versão 1 - julho/2013
Obtendo as facetas IReceptacles do Stock. Seller e Exchange. Printer do Stock. Logger ORB orb = Orb. Services. Get. Singleton(); // Obtém as referências para os objetos CORBA IComponent seller. IC = orb. string_to_object(seller. IOR) as IComponent; if (seller. IC == null) {. . . } IComponent logger. IC = orb. string_to_object(logger. IOR) as IComponent; if (logger. IC == null) {. . . } string receptacles. Type = Repository. Get. Repository. ID(typeof (IReceptacles)); IReceptacles ir. Stock. Seller = seller. IC. get. Facet(receptacles. Type) as IReceptacles; if (ir. Stock. Seller == null) {. . . } string printer. Type = Repository. Get. Repository. ID(typeof (Exchange. Printer)); Exchange. Printer printer = logger. IC. get. Facet(printer. Type) as Exchange. Printer; if (printer == null) {. . . } • Precisaremos da faceta Exchange. Printer do componente Stock. Logger, pois é essa faceta que será conectada ao receptáculo do Stock. Seller • A faceta IComponent tem métodos para recuperar suas outras facetas versão 1 - julho/2013
Conectando a faceta Exchange. Printer do Stock. Logger no receptáculo do Stock. Seller // Faz a conexão da faceta Exchange. Printer do componente Stock. Logger no // receptáculo do Stock. Seller ir. Stock. Seller. connect("Exchange. Printer", printer); • Usamos a faceta IReceptacles de Stock. Seller para fazer a conexão dos componentes • O método connect faz a conexão do componente Stock. Logger usando sua faceta Exchange. Printer • 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 1 - julho/2013
Passo 6: Usando os componentes conectados ao receptáculo do Stock. Seller • A implementação do método buy. Stock pela faceta Stock. Exchange do componente Stock. Seller deve chamar o método print da faceta Exchange. Printer conectada a esse mesmo componente versão 1 - julho/2013
Obtendo o receptáculo correspondente a Exchange. Printer public bool buy. Stock(string symbol) {. . . IList<Connection. Description> conns = _context. Get. Receptacle. By. Name( "Exchange. Printer"). Get. Connections(); foreach (Connection. Description conn in conns) { try { ((Exchange. Printer)conn. objref). print( "Negociação da ação " + symbol + ". Novo valor: " + value); } catch(. . . ) {. . . } }. . . } • O contexto do componente possui o método Get. Receptacle. By. Name 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 Get. Connections de Receptacle • O campo objref de Connection. Description possui a referência para a faceta IComponent da dependência conectada versão 1 - julho/2013
Passo 7: Usando o componente Stock. Seller • O cliente usa o componente Stock. Seller através de suas facetas • O Stock. Market. Client. cs 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 1 - julho/2013
Obtendo a referência para o componente Stock. Seller // Lê o IOR do arquivo cujo nome é passado como parâmetro string ior = File. Read. All. Text(args[0]); ORB orb = Orb. Services. Get. Singleton(); // Obtém a referência para o objeto CORBA IComponent seller. IC = orb. string_to_object(ior) as IComponent; if (seller. IC == null) {…} • O cliente recupera a referência para o componente Stock. Seller lendo do arquivo recebido por parâmetro versão 1 - julho/2013
Obtendo as facetas Stock. Server e Stock. Exchange do componente Stock. Seller try { string server. Type = Repository. Get. Repository. ID(typeof(Stock. Server)); string exchange. Type = Repository. Get. Repository. ID(typeof(Stock. Exchange)); Stock. Server server = seller. IC. get. Facet(server. Type) as Stock. Server; if (server == null) {. . . } Stock. Exchange exchange = seller. IC. get. Facet(exchange. Type) as Stock. Exchange; if (exchange == null) {. . . } } catch (…) { … } • Tendo o componente, as facetas Stock. Server e Stock. Exchange são recuperadas, pelo nome ou pela interface versão 1 - julho/2013
Invocando os métodos disponibilizados em cada faceta try { // Obtém os símbolos de todas as ações string[] symbols = server. get. Stock. Symbols(); // Mostra as ações com seus respectivos valores foreach (string symbol in symbols) { Console. Write. Line(symbol + " " + server. get. Stock. Value(symbol)); } // Compra uma ação if (symbols. Length > 0) { String first = symbols[0]; Console. Write. Line("--Compra a ação : " + first); bool success = exchange. buy. Stock(first); if (success) { Console. Write. Line("--Ação " + first + " depois da negociação: " + server. get. Stock. Value(first)); } else { Console. Write. Line("--Não foi possivel negociar a ação " + first); } } } catch (…) {…} • O cliente faz as chamadas aos métodos usando as respectivas facetas versão 1 - julho/2013
- Slides: 49