Desenvolvendo uma aplicação CORBA utilizando Java Tecgraf PUC-Rio fevereiro de 2011
Exemplo passo-a-passo Veremos um exemplo, passo-a-passo, de desenvolvimento de aplicações CORBA usando Java Para desenvolver a aplicação, usaremos o Jacorb como ORB tanto para o cliente quanto para o servidor, já que ambos serão desenvolvidos em Java
Passo 1: Jacorb e SDK A última versão do Jacorb pode ser obtida de: http://www.jacorb.org Precisaremos também do JDK 1.5 ou superior Para fazer build do exemplo, usaremos o Ant: http://ant.apache.org/
Libs do Jacorb antlr-2.7.2.jar avalon-framework-4.1.5.jar backport-util-concurrent.jar idl.jar jacorb-2.3.0.jar logkit-1.2.jar picocontainer-1.2.jar wrapper-3.1.0.jar
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 { // 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 do marcado identificada por um // StockSymbol fornecido como parâmetro de entrada. // Se o StockSymbol dado for desconhecido, o resultado // é indefinido. Depois veremos como usar uma exceção // para sinalizar essa condição. float getstockvalue(in StockSymbol symbol); ; ; // getstocksymbols() retorna uma sequência com todos os // StockSymbols conhecidos pelo servidor do mercado de // ações. StockSymbolList getstocksymbols();
Passo 3: Compilando a IDL Para compilar a IDL, usaremos o Ant e o compilador IDL do Jacorb: <!-- =================================================== --> <!-- Inicializacao --> <!-- ==================================================== --> <target name="init" description="inicia as propriedades"> <property name="lib" value="lib"/> <property name="idl" value="idl"/> <property name="generated" value="generated"/> <property name="jacorb" value="jacorb"/> </target> <!-- ==================================================== --> <!-- IDL compiler --> <!-- ==================================================== --> <target name="idl" depends="clean" description="compila as idls"> <delete dir="${generated"/> <java classname="org.jacorb.idl.parser" fork="yes"> <classpath> <pathelement location="${lib/${jacorb/idl.jar"/> <pathelement location="${lib/${jacorb/logkit-1.2.jar"/> </classpath> <arg line="-d ${generated ${idl/stockmarket.idl"/> </java> </target>
Arquivos gerados na compilação da IDL Todas as classes estão dentro do pacote StockMarket StockServer.java StockServerOperations.java StockServerHelper.java StockSymbolHelper.java StockSymbolListHelper.java StockServerHolder.java StockSymbolListHolder.java Interface Files Helper Files Holder Files StockServerPOA.java StockServerPOATie.java _StockServerStub.java Stubs e Skeleton Files
Interface Files A interface IDL StockServer é mapeada para: uma interface java de assinatura StockServer.java uma interface java de operações StockServerOperations.java A interface de assinatura possui o mesmo nome da interface IDL, estende outras interfaces CORBA e é usada como o tipo referenciado em outras interfaces. A interface de operações possui o nome da interface IDL junto com o sufixo Operations e é uma interface java pura, ou seja, possui apenas as declarações das operações e atributos definidos na interface IDL
StockServerOperations.java package StockMarket; /** * Generated from IDL interface "StockServer". * * @author JacORB IDL compiler V 2.3-beta-2, 14-Oct-2006 * @version generated at Oct 19, 2010 5:47:22 PM */ public interface StockServerOperations { /* constants */ /* operations */ float getstockvalue(java.lang.string symbol); java.lang.string[] getstocksymbols();
StockServer.java package StockMarket; /** * Generated from IDL interface "StockServer". * * @author JacORB IDL compiler V 2.3-beta-2, 14-Oct-2006 * @version generated at Oct 19, 2010 5:47:22 PM */ public interface StockServer extends StockServerOperations, org.omg.corba.object, org.omg.corba.portable.idlentity { org.omg.corba.object: é a interface raiz para todas as referências a objetos CORBA na linguagem Java, análogo a interface java.rmi.remote para os objetos remotos RMI. org.omg.corba.portable.idlentity: interface de marcação cuja finalidade é apenas indicar que a classe que implementa essa interface é um tipo IDL que possui uma classe de Helper correspondente.
Stub e Skeleton Files A compilação da IDL StockServer produz a classe _StockServerStub.java que atua como stub do cliente e as classes StockServerPOA.java e StockServerPOATie.java que servem de skeleton do servidor. Veremos depois que o uso das classes de skeleton POA ou POATie depende da estratégia adotada para implementação do servidor: por herança ou por delegação
_StockServerStub.java package StockMarket;! /**! * Generated from IDL interface "StockServer".! *! * @author JacORB IDL compiler V 2.3-beta-2, 14-Oct-2006! * @version generated at Oct 25, 2010 3:50:57 PM! */! public class _StockServerStub! extends org.omg.corba.portable.objectimpl! implements StockMarket.StockServer {!...! public float getstockvalue(java.lang.string symbol) {!...! public java.lang.string[] getstocksymbols() {!...!
StockServerPOA.java package StockMarket;! /**! * Generated from IDL interface "StockServer".! *! * @author JacORB IDL compiler V 2.3-beta-2, 14-Oct-2006! * @version generated at Oct 25, 2010 3:50:57 PM! */! public abstract class StockServerPOA! extends org.omg.portableserver.servant! implements org.omg.corba.portable.invokehandler,! StockMarket.StockServerOperations! {!...!
StockServerPOATie.java package StockMarket;! import org.omg.portableserver.poa;! /**! * Generated from IDL interface "StockServer".! *! * @author JacORB IDL compiler V 2.3-beta-2, 14-Oct-2006! * @version generated at Oct 25, 2010 3:50:57 PM! */! public class StockServerPOATie! extends StockServerPOA! {!...! private StockServerOperations _delegate;! public StockServerPOATie(StockServerOperations delegate)! {! _delegate = delegate;! public float getstockvalue(java.lang.string symbol)! {! return _delegate.getstockvalue(symbol);! public java.lang.string[] getstocksymbols()! {! return _delegate.getstocksymbols();!
Helper Files A compilação da IDL StockServer produz as classes de Helper StockServerHelper.java, StockSymbolHelper.java e StockSymbolListHelper.java As classes de Helper oferecem diversos métodos estáticos úteis na manipulação do tipo correspondente: inserir e extrair um objeto do tipo em Any obter o repository id ler de um stream e escrever para um stream
Helper Files A classe de Helper gerada a partir de uma interface IDL, também inclui operações de narrow para converter o tipo genérico org.omg.corba.object para o tipo específico. A exceção IDL CORBA::BAD_PARAM é lançada se a conversão do narrow falhar devido a inconsitência do tipo da referência do objeto.
StockSymbolHelper.java package StockMarket;! /*! * Generated from IDL alias "StockSymbol".! *! * @author JacORB IDL compiler V 2.3-beta-2, 14-Oct-2006! * @version generated at Oct 19, 2010 5:47:22 PM! */! public final class StockSymbolHelper {!...! public static void insert (org.omg.corba.any any, java.lang.string s) {!...! public static java.lang.string extract (final org.omg.corba.any any) {!...! public static String id() {! return "IDL:StockMarket/StockSymbol:1.0";! public static java.lang.string read (! final org.omg.corba.portable.inputstream _in) {!...! public static void write (! final org.omg.corba.portable.outputstream _out, java.lang.string _s) {!...!
StockServerHelper.java package StockMarket;! /**! * Generated from IDL interface "StockServer".! *! * @author JacORB IDL compiler V 2.3-beta-2, 14-Oct-2006! * @version generated at Oct 19, 2010 5:47:22 PM! */! public final class StockServerHelper {! // Todos os métodos estáticos insert, extract, type, id, read e write! // e mais os métodos de conversão narrow!...! public static StockMarket.StockServer narrow(final org.omg.corba.object obj)! {!...! public static StockMarket.StockServer unchecked_narrow(! final org.omg.corba.object obj)! {!...!
Holder Files Os métodos definidos nas interfaces IDL que tem passagem de parâmetros nos modos out a inout, requerem o uso de classes de Holder. Todos os tipos primitivos da IDL possuem as classes de Holder disponíveis no pacote org.omg.corba package O compilador IDL gera as classes de Holder para todos os tipos definidos pelo desenvolvedor (exceto aqueles definidos por typedef) A compilação da IDL StockServer produz as classes de Holder StockServerHolder.java e StockSymbolListHolder.java
StockSymbolListHolder.java package StockMarket; /** * Generated from IDL alias "StockSymbolList". * * @author JacORB IDL compiler V 2.3-beta-2, 14-Oct-2006 * @version generated at Oct 19, 2010 5:47:22 PM */ public final class StockSymbolListHolder implements org.omg.corba.portable.streamable { public java.lang.string[] value; public StockSymbolListHolder () { public StockSymbolListHolder (final java.lang.string[] initial) { value = initial; public org.omg.corba.typecode _type () { return StockSymbolListHelper.type (); public void _read (final org.omg.corba.portable.inputstream in) { value = StockSymbolListHelper.read (in); public void _write (final org.omg.corba.portable.outputstream out) { StockSymbolListHelper.write (out,value);
StockServerHolder.java package StockMarket; /** * Generated from IDL interface "StockServer". * * @author JacORB IDL compiler V 2.3-beta-2, 14-Oct-2006 * @version generated at Oct 19, 2010 5:47:22 PM */ public final class StockServerHolder implements org.omg.corba.portable.streamable{ public StockServer value; public StockServerHolder() { public StockServerHolder (final StockServer initial) { value = initial; public org.omg.corba.typecode _type() { return StockServerHelper.type(); public void _read (final org.omg.corba.portable.inputstream in) { value = StockServerHelper.read (in); public void _write (final org.omg.corba.portable.outputstream _out) { StockServerHelper.write (_out,value);
Passo 4: Compilando o código java Para compilar o código Java gerado pela IDL, usaremos o Ant e o compilador javac <!-- ==================================================== -->! <!-- Java Compiler -->! <!-- ==================================================== -->! <target name="javac" depends="idl" description="compila o codigo java">! <!-- Cria o diretorio para compilacao -->! <mkdir dir="${build" />! <!-- Compila os fontes do src e do gerenerated -->! <javac destdir="${build"! debug="on"! encoding="iso-8859-1">! <src path="${generated"/>! <src path="${src"/>! </javac>! </target>!
Passo 5: Implementando o Servant O Servant que implementa a interface definida na IDL StockServer pode ser uma classe que estende a classe abstrata StockServerPOA ou pode ser uma classe simples cuja instância é passada para a classe de delegação StockServerPOATie. Para compilar o Servant, o compilador java deve ter no classpath as classes de skeleton, as classes de interface e as classes Helper e Holder geradas pelo compilador IDL.
Estratégias de implementação CORBA suporta dois mecanismos para implementação da IDL por uma classe Servant por herança por delegação A diferença principal entre os dois mecanismos é que, pelo mecanismo de delegação, a classe de implementação da IDL não precisa derivar de uma classe em particular
Usando herança package StockMarket; /* * StockServerImpl implementa a interface IDL StockServer */ public class StockServerImpl extends StockServerPOA { // As ações com seus respectivos valores private Map<String, Float> mystock; public StockServerImpl() { mystock = new HashMap<String,Float>(); // Inicializa as ações com nomes e valores // atribuídos randomicamente... public float getstockvalue(string symbol) { if (mystock.containskey(symbol)) { // Simbolo encontrado; retorna seu valor return mystock.get(symbol); else { // Simbolo não foi encontrado return 0f; public String[] getstocksymbols() { return mystock.keyset().toarray(new String[0]);
Usando delegação package StockMarket; /** * StockServerImpl implementa a interface IDL StockServer usando * o mecanismo de delegação */ public class StockServerTieImpl implements StockServerOperations { // As ações com seus respectivos valores private Map<String, Float> mystock; public StockServerImpl() { mystock = new HashMap<String,Float>(); // Inicializa as ações com nomes e valores // atribuídos randomicamente... public float getstockvalue(string symbol) { if (mystock.containskey(symbol)) { // Simbolo encontrado; retorna seu valor return mystock.get(symbol); else { // Simbolo não foi encontrado return 0f; public String[] getstocksymbols() { return mystock.keyset().toarray(new String[0]);
Passo 6: Implementando o servidor O programa servidor se encarrega de: inicializar o ORB criar o objeto Servant StockServerImpl exportar o Servant para o POA aguardar que o cliente envie requisições Para compilar o servidor, o compilador java deve ter no classpath as classes de interface, a classe do skeleton, as classes Helper e Holder geradas pelo compilador IDL e, a classe do Servant.
Inicializa o 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");! ORB orb = ORB.init(args, orbprops);! init public static ORB init(string[] args, Properties props) Creates a new ORB instance for a standalone application. This method may be called from applications only and returns a new fully functional ORB object each time it is called. Parameters: args - command-line arguments for the application's main method; may be null props - application-specific properties; may be null Returns: the newly-created ORB instance
Cria o Servant que implementa a IDL Se o Servant tiver adotado a estratégia de implementação por herança: Servant stockserver = new StockServerImpl();! Se o Servant tiver adotado a estratégia de implementação por delegação: Servant stockserver = new StockServerPOATie(new StockServerImpl());!
Cria o Servant que implementa a IDL Note que, até aqui, temos apenas um objeto Java instanciado. Precisamos agora tornar esse objeto um objeto CORBA, capaz de receber as requisições dos clientes. Usaremos, para isso, o POA.
Exporta o Servant para o POA POA poa = POAHelper.narrow(orb.resolve_initial_references("RootPOA"));! poa.the_poamanager().activate();! org.omg.corba.object o = poa.servant_to_reference(stockserver);! Obtém uma referência para uma instância do POA Após fazer narrow da referência, é necessário ativar o POA (seu estado inicial é on-holding) Registra o Servant no POA
Bloqueia a thread corrente para o ORB orb.run();! Bloqueia a thread corrente até o ORB terminar
Exemplo do servidor do StockServer package StockMarket;! import java.io.*;! import org.omg.corba.orb;! import org.omg.portableserver.*;! public class StockServerMain {! public static void main(string args[]) {! try {! // Inicializa o 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");! ORB orb = ORB.init(args, orbprops);! // Cria o Servant StockServerImpl que implementa a IDL! Servant stockserver = new StockServerImpl();! // Obtém uma referência para o POA e registra o Servant nesse POA! POA poa = POAHelper.narrow(orb.resolve_initial_references("RootPOA"));! poa.the_poamanager().activate();! org.omg.corba.object o = poa.servant_to_reference(stockserver);! // Escreve no arquivo a referência para o objeto CORBA! PrintWriter ps = new PrintWriter( new FileOutputStream(! new File( args[0] )));! ps.println(orb.object_to_string( o ));! ps.close();! // Bloqueia a thread corrente até o ORB finalizar! orb.run();! catch (Exception ex) {! ex.printstacktrace();!
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 módulo cliente deve ter no classpath a classe de stub _StockServerStub, a classe de assinatura StockServer e as classes Helper e Holder geradas pelo compilador IDL
Exemplo do cliente do StockServer package StockMarket;! import java.io.*! import org.omg.corba.orb;! public class StockServerClient {! public static void main(string args[]) {! try {! // 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);! // Lê o IOR do arquivo cujo nome é passado como parâmetro! BufferedReader reader =! new BufferedReader(new InputStreamReader(new FileInputStream(args[0])));! String ior = reader.readline();! // Obtém a referência para objeto CORBA! org.omg.corba.object obj = orb.string_to_object(ior);! StockServer mystock = StockServerHelper.narrow(obj);! // Executa as chamadas ao objeto CORBA! StockServerClient stockclient = new StockServerClient(myStock);! stockclient.run();! catch (Exception e) {! e.printstacktrace();!
Exemplo do cliente do StockServer package StockMarket;! import java.io.*! import org.omg.corba.orb;! public class StockServerClient {! private StockServer mystock;! public StockServerClient(StockServer mystock) {! this.mystock = mystock;! public void run() {! try {! System.out.println( Ações de mercado obtidas do StockServer:");! // Obtém os símbolos de todos as ações! String[] stocksymbols = mystock.getstocksymbols();! // Mostra as ações com seus respectivos valores! for (int i = 0; i < stocksymbols.length; i++) {! System.out.println(stockSymbols[i] + " "! + mystock.getstockvalue(stocksymbols[i]));! catch (org.omg.corba.systemexception e) {! e.printstacktrace();! public static void main(string args[]) {!...!
Passo 8: Executando o servidor java -cp./build: lib/jacorb/antlr-2.7.2.jar: lib/jacorb/avalon-framework-4.1.5.jar: lib/jacorb/backport-util-concurrent.jar: lib/jacorb/idl.jar:lib/jacorb/jacorb-2.3.0.jar: lib/jacorb/logkit-1.2.jar: lib/jacorb/picocontainer-1.2.jar: lib/jacorb/wrapper-3.1.0.jar StockMarket.StockServerMain ior
Saída da execução do servidor mjulia$./runserver Ações do mercado criadas: 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
Passo 9: Executando o cliente java -cp./build: lib/jacorb/antlr-2.7.2.jar: lib/jacorb/avalon-framework-4.1.5.jar: lib/jacorb/backport-util-concurrent.jar: lib/jacorb/idl.jar:lib/jacorb/jacorb-2.3.0.jar: lib/jacorb/logkit-1.2.jar: lib/jacorb/picocontainer-1.2.jar: lib/jacorb/wrapper-3.1.0.jar StockMarket.StockServerClient ior
Saída da execução do cliente mjulia$./runclient Ações de mercado 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