Desenvolvendo uma aplicação CORBA utilizando C# Tecgraf PUC-Rio Novembro de 2013 versão 1 - julho/2013 Exemplo passo-a-passo • Veremos um exemplo, passo-a-passo, de desenvolvimento de aplicações CORBA usando C# • Para desenvolver a aplicação, usaremos o IIOP.NET como ORB tanto para o cliente quanto para o servidor, já que ambos serão desenvolvidos em C# versão 1 - julho/2013 Passo 1: IIOP.NET e .NET • Para o OpenBus, precisaremos de uma versão alterada do IIOP.NET, com algumas correções e novas funcionalidades. Essa versão pode ser obtida: • Do pacote do exercício, no site do curso • Dos pacotes mais recentes do OpenBus ou SCS, em seus respectivos sites • Precisaremos também do .NET Framework 4.0 • Para compilar o exemplo, usaremos o Visual Studio 2010 versão 1 - julho/2013 Libs do Pacote do Exercício • Para o seu programa: • IIOPChannel.dll • Para o compilador de IDL: • IIOPChannel.dll • IDLPreprocessor.dll versão 1 - julho/2013 Passo 2: Escrevendo 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 { // Exceção para definir o uso de um símbolo desconhecido exception UnknownSymbol { string symbol; }; // O tipo StockSymbol é usado para representar os // identificadores das ações typedef string StockSymbol; // Um StockSymbolList é uma sequência de StockSymbols. typedef sequence<StockSymbol> StockSymbolList; // A interface StockServer é a interface que fornece // as informações sobre as ações do mercado. interface StockServer { // getStockValue() retorna o valor de uma // determinada ação identificada por um // StockSymbol fornecido como parâmetro de entrada. // Se o StockSymbol dado for desconhecido, a exceção // UnknownSymbol deve ser lançada. float getStockValue(in StockSymbol symbol); }; }; // getStockSymbols() retorna uma sequência com todos os // StockSymbols conhecidos pelo servidor do mercado de // ações. StockSymbolList getStockSymbols(); versão 1 - julho/2013 Passo 3: Compilando a IDL • Para compilar a IDL, usaremos o compilador IDL do IIOP.NET: IDLToCLSCompiler.exe -asmVersion 1.0.0 StockMarket.Idl StockMarket.idl • Todas as classes estarão dentro da biblioteca StockMarket.Idl.dll • Para essa idl apenas a interface StockServer será gerada • Caso existam ValueTypes na idl, pode-se passar a opção –vtSkel para que esqueletos sejam gerados automaticamente versão 1 - julho/2013 Interface Files • A interface IDL StockServer é mapeada para: – uma interface C# de assinatura StockServer • A interface de assinatura possui o mesmo nome da interface IDL, estende outras interfaces CORBA e é usada como o tipo referenciado em outras interfaces versão 1 - julho/2013 StockServer.cs // Type: StockMarket.StockServer // Assembly: StockMarket.Idl, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null // Assembly location: StockMarket.Idl.dll using Ch.Elca.Iiop.Idl; namespace StockMarket { [RepositoryID("IDL:StockMarket/StockServer:1.0")] [InterfaceType(IdlTypeInterface.ConcreteInterface)] public interface StockServer : IIdlEntity { [FromIdlName("getStockValue")] float getStockValue([StringValue, WideChar(false)] string symbol); [FromIdlName("getStockSymbols")] [return: IdlSequence(0L)] [return: WideChar(false)] [return: StringValue] string[] getStockSymbols(); } } Ch.Elca.Iiop.Idl.IDLEntity: interface de “marcação” cuja finalidade é apenas indicar que a classe que implementa essa interface é um tipo IDL versão 1 - julho/2013 Classes de apoio do IIOP.NET • O IIOP.NET permite apenas uma instância de ORB, e essa instância é um singleton OrbServices orb = OrbServices.GetSingleton(); • A classe OrbServices oferece diversas funcionalidades devido à fuga do padrão CORBA: – Funcionalidades do ORB – Incluindo criação de tipos IDL para inserção em any – Métodos que estariam no CORBA::Object – _is_a(), _non_existent() – Métodos relacionados à interceptação versão 1 - julho/2013 Classes de apoio do IIOP.NET • A classe ChannelServices oferece funcionalidades para: – Registro de canais de comunicação – URLs de objetos (URLs são object ids de CORBA) • Para enviar ou receber chamadas, é necessário estabelecer um canal de comunicação • Servidores devem especificar uma porta (0 para aleatória) IiopChannel chan = new IiopChannel(0); ChannelServices.RegisterChannel(chan, false); versão 1 - julho/2013 Classes de apoio do IIOP.NET • O IIOP.NET não implementa o conceito de POA para o usuário • Mas permite a configuração de algumas políticas (FAQ) • Para registrar um servant, deve-se utilizar: RemotingServices.Marshal(servant); • Existe um método análogo, Unmarshal • Essa classe possui alguns outros métodos estáticos com funcionalidades que seriam do POA versão 1 - julho/2013 Classes de apoio do IIOP.NET • A classe Ch.Elca.Iiop.Idl.Repository oferece funcionalidades relacionadas ao repositório de interfaces, como a obtenção do RepositoryId de um tipo idl: Ch.Elca.Iiop.Idl.Repository.GetRepositoryID(typeof (Node)); • Não existe um método narrow; o typecast deve ser feito como em typecasts C# comuns versão 1 - julho/2013 Passo 4: Compilando o código C# • Para compilar seu código, adicione a biblioteca com os símbolos gerados a partir da idl como dependência (StockMarket.Idl.dll) • Adicione também a biblioteca do IIOP.NET (IIOPChannel.dll) • Você deve utilizar a mesma versão que foi utilizada pelo compilador IDL versão 1 - julho/2013 Passo 5: Implementando o Servant • O servant que implementa a interface definida na IDL StockServer deve ser uma classe que: • Implemente a interface C# StockServer • Estenda a classe abstrata MarshalByRefObject • O nome do servant pode ser qualquer um; por exemplo, StockServerImpl versão 1 - julho/2013 Tempo de Vida do Servant • Para que seu servant não seja coletado em um momento indefinido você deve fornecer uma política de tempo de vida, sobrescrevendo o método InitializeLifetimeService(). Para que ele nunca seja coletado, basta retornar null public override object InitializeLifetimeService() { return null; } versão 1 - julho/2013 Exemplo de Implementação using System; using System.Collections.Generic; namespace StockMarket { public class StockServerImpl : MarshalByRefObject, StockServer { // neste exemplo só há leituras no mapa, então não precisamos // nos preocupar com concorrência private readonly IDictionary<string, float> _myStock; private readonly string[] _symbols; public StockServerImpl() { _myStock = new Dictionary<string, float>(); //Inicializa as ações com nomes e valores // fixos ou atribuídos randomicamente ... _symbols = new string[_myStock.Count]; _myStock.Keys.CopyTo(_symbols, 0); } public float getStockValue(string symbol) { float value; _myStock.TryGetValue(symbol, out value); return value; } public string[] getStockSymbols() { return _symbols; } } } versão 1 - julho/2013 Passo 6: Implementando o servidor • O programa servidor se encarrega de: – – – – – inicializar o ORB criar o objeto Servant StockServerImpl registrar o Servant no ORB publicar sua referência aguardar que o cliente envie requisições • Para compilar o servidor, o compilador .NET deve ter acesso à classe de interface e à classe do Servant versão 1 - julho/2013 Inicializa o ORB • Não é necessário inicializar a única instância de ORB • É necessário estabelecer um canal de comunicação // Inicializa o ORB, indicando que utilize uma porta aleatória para receber chamadas IiopChannel chan = new IiopChannel(0); ChannelServices.RegisterChannel(chan, false); versão 1 - julho/2013 Cria o Servant que implementa a IDL StockServerImpl stockServer = new StockServerImpl(); versão 1 - julho/2013 Cria o Servant que implementa a IDL • Note que, até aqui, temos apenas um objeto C# instanciado, capaz de receber requisições • Precisamos agora tornar esse objeto conhecido pelo ORB, para que direcione chamadas recebidas a ele RemotingServices.Marshal(stockServer); versão 1 - julho/2013 Publica a referência do objeto CORBA • A interface omg.org.CORBA.ORB tem um método para obter a referência de um objeto CORBA em uma string • Basta obter essa string a partir do singleton do ORB, e em seguida publicá-la de alguma forma (ex: arquivo) ORB orb = OrbServices.GetSingleton(); string ior = orb.object_to_string(stockServer); versão 1 - julho/2013 Bloqueia a thread corrente Thread.Sleep(Timeout.Infinite); • Bloqueia a thread corrente indefinidamente versão 1 - julho/2013 Passo 7: Implementando o cliente • O programa cliente se encarrega de: – inicializar o ORB – obter a referência para o objeto CORBA StockServer – fazer chamadas aos métodos definidos pela IDL do StockServer • O compilador .NET deve ter acesso à classe de interface gerada pelo compilador IDL versão 1 - julho/2013 Exemplo do cliente do StockServer namespace StockMarket { internal static class StockMarketServer { private static void Main(String[] args) { // Inicializa o ORB IiopClientChannel channel = new IiopClientChannel(); ChannelServices.RegisterChannel(channel, false); // Lê o IOR do arquivo cujo nome é passado como parâmetro string ior = File.ReadAllText(args[0]); ORB orb = OrbServices.GetSingleton(); // Obtém a referência para o objeto CORBA StockServer server = orb.string_to_object(ior) as StockServer; if (server == null) { Console.WriteLine("Arquivo de IOR com referência inválida."); return; } // Executa chamadas ao objeto CORBA . . . } } } versão 1 - julho/2013 Exemplo do cliente do StockServer namespace StockMarket { internal static class StockMarketServer { private static void Main(String[] args) { . . . // Executa chamadas ao objeto CORBA try { Console.WriteLine("Ações obtidas do StockServer:"); // Obtém os símbolos de todas as ações: string[] symbols = server.getStockSymbols(); // Mostra as ações com seus respectivos valores foreach (string symbol in symbols) { Console.WriteLine(symbol + " " + server.getStockValue(symbol)); } } catch (UnknownSymbol e) { Console.WriteLine("O símbolo " + e.symbol + " não existe."); } catch (TRANSIENT) { Console.WriteLine("O serviço encontra-se indisponível."); } catch (COMM_FAILURE) { Console.WriteLine("Falha na comunicação com o serviço."); } } } } versão 1 - julho/2013 Passo 8: Executando o servidor Server.exe ior.txt versão 1 - julho/2013 Saída da execução do servidor Ações UION: LGBA: ZZSP: KLVV: ZDZR: UFTH: DNKS: AQVS: AZHM: PEMR: criadas: 18.192759 46.23733 48.71345 57.355362 41.779728 74.87004 80.69647 99.87545 72.27951 35.293213 Servidor rodando. versão 1 - julho/2013 Passo 9: Executando o cliente Client.exe ior.txt versão 1 - julho/2013 Saída da execução do cliente Ações obtidas do StockServer: UION 18.192759 LGBA 46.23733 ZZSP 48.71345 KLVV 57.355362 ZDZR 41.779728 UFTH 74.87004 DNKS 80.69647 AQVS 99.87545 AZHM 72.27951 PEMR 35.293213 versão 1 - julho/2013