SDK Openbus - Java Tecgraf PUC-Rio maio de 2011 A API do Openbus • Para facilitar o desenvolvimento das aplicações que usam o barramento, provendo ou consumindo serviços, o SDK Java fornece uma classe Openbus que encapsula as principais funcionalidades para: • inicialização e conexão com o barramento. • obtenção das facetas dos serviços básicos. • obtenção do ORB e do POA utilizados • A própria classe OpenBus já cuida da renovação da credencial emitida na conexão Openbus é um Singleton • Uma aplicação pode ter apenas uma instância de Openbus. • atualmente, uma nesma aplicação não pode utilizar dois barramentos diferentes public static Openbus getInstance(); Inicialização do barramento • Possui métodos para inicializar o ORB com as propriedades informadas e faz reset no estado do barramento. • Ativa o mecanismo de interceptação das requisições para que a credencial seja utilizada • Ativa o POA “RootPOA” public void init(String[] args, Properties props, String host, int port) throws UserException, OpenbusAlreadyInitializedException; Conexão com o barramento • Os métodos de inicialização são sobrecarregados para diferentes formas de conexão com o barramento • Todos retornam a referência para o IRegistryService public synchronized IRegistryService connect(String user, String password) throws ACSLoginFailureException, ACSUnavailableException, ServiceUnavailableException, InvalidCredentialException, CORBAException, OpenBusException; public synchronized IRegistryService connect(String name, RSAPrivateKey privateKey, X509Certificate acsCertificate) throws ACSLoginFailureException, ServiceUnavailableException, PKIException, ACSUnavailableException, InvalidCredentialException, OpenBusException, CORBAException; public IRegistryService connect(Credential credential) throws InvalidCredentialException, OpenBusException, ServiceUnavailableException, ACSUnavailableException, CORBAException; Listener para expiração da credencial • Possui um método que permite adicionar um listener que é avisado quando a credencial expirou e não foi possível renovar o leasing. public void setLeaseExpiredCallback(LeaseExpiredCallback lec); • O listener é chamado pela thread que faz a renovação automática do leasing, que a própria instância do Openbus já inicia. Credencial por Thread • Possui o método setThreadCredential que permite que uma credencial válida, diferente daquela que foi usada na conexão, seja configurada para a thread corrente. • As requisições aos serviço usam a credencial atribuída à thread corrente, caso exista. public void setThreadCredential(Credential credential); Credencial por Thread • Um uso comum da credencial por thread é criar uma nova credencial como uma cópia daquela resultado da autenticação corrente, alterando apenas o delegate. Credential credential = Openbus.getInstance().getCredential(); Credential newCredential = new Credential(credential.identifier, credential.owner, delegate); Openbus.getInstance().setThreadCredential(newCredential); Acesso aos serviços básicos • Possui métodos para obter as referências para as facetas do serviços básicos: • IAccessControlService • IRegistryService • ISessionService public IAccessControlService getAccessControlService(); public IRegistryService getRegistryService(); public ISessionService getSessionService(); Acesso aos ORB e ao POA • Possui métodos para obter as referências para as ORB utilizado e ao POA “RootPOA”: public org.omg.CORBA.ORB getORB(); public POA getRootPOA(); Finaliza a conexão • Possui um métod para suspender a renovação da credencial e fazer logout no serviço de acesso public synchronized boolean disconnect(); Outras classes auxiliares • • • • CryptoUtils Log LeaseExpiredCallback … Desenvolvendo com o SDK Java Openbus Passo 1: Obtendo o SDK Openbus • A última versão do SDK Java do Openbus pode ser obtida em: • https://jira.tecgraf.pucrio.br/confluence/display/ESDPUB/Openbus+Do wnload • Precisaremos também do JDK 1.5 ou superior Libs do SDK Openbus 1.5 • Openbus: • openbus-api-1.5.0.jar • openbus-idl-jacorb-1.5.0.jar • As libs do Jacorb são distribuídas com o SDK: • avalon-framework-4.1.5.jar • jacorb-2.3.0.jar • logkit-1.2.jar • As libs do SCS são distribuídas com o SDK: • scs-core-1.1.0.jar • scs-idl-jacorb-1.1.0.jar • A lib para encoding: • commons-codec-1.3.jar Passo 2: Preparando os stubs e skeletons • Usaremos como base, as mesmas IDLs do exemplo StockServer mostrado na parte de CORBA e do SCS • Compilar a IDL • Compilar o código Java das classes geradas pelo compilador IDL e das classes que implementam as facetas descritas na IDL Passo 3: Implementando as facetas do componente • O componente StockSeller possui duas facetas: • StockServer • StockExchanger • As classes StockServerImpl e StockExchangeImpl implementam, respectivamente, cada uma dessas facetas. • Para compartilhar o estado entre as duas facetas, iremos implementar a classe StockSellerContextImpl de contexto do componente. Implementando o contexto StockSellerContextImpl public class StockSellerContextImpl extends ComponentContextImpl { /** As ações com seus respectivos valores */ private Map<String, Float> myStock; ... public StockSellerContextImpl(ComponentBuilder builder, ComponentId componentId) { super(builder, componentId); ... } public synchronized boolean containsStockSymbol(String symbol) { return myStock.containsKey(symbol); } public synchronized float getStockValue(String symbol) { return myStock.get(symbol); } public synchronized String[] getAllSymbols() { return myStock.keySet().toArray(new String[0]); } public synchronized void decrementStockValue(String symbol, float value) { float newValue = getStockValue(symbol) - value; myStock.put(symbol, newValue); } Implementando a faceta (Servant) StockServer public class StockServerImpl extends StockServerPOA { private StockSellerContextImpl context; public StockServerImpl(ComponentContext context) { this.context = StockSellerContextImpl.class.cast(context); } public float getStockValue(String symbol) { if (context.containsStockSymbol(symbol)) { return context.getStockValue(symbol); } else { return 0f; } } public String[] getStockSymbols() { return context.getAllSymbols(); } public org.omg.CORBA.Object _get_component() { return context.getIComponent(); } } Implementando a faceta (Servant) StockExchange public class StockExchangeImpl extends StockExchangePOA { StockSellerContextImpl context; public StockExchangeImpl(ComponentContext context) { this.context = StockSellerContextImpl.class.cast(context); } public boolean buyStock(String symbol) { if (!context.containsStockSymbol(symbol) || context.getStockValue(symbol) == 0.0F) { return false; } context.decrementStockValue(symbol, 1); return true; } public org.omg.CORBA.Object _get_component() { return context.getIComponent(); } Passo 4: Implementando o Servidor • O programa servidor se encarrega de: – inicializar o Openbus – fazer a conexão por certificado – criar o componente que implementa as facetas StockServer e StockExchange – registrar uma oferta de serviço – instalar um ShutdownHook para desconectar com o barramento antes de finalizar a aplicação – iniciar a execução do ORB Fluxo principal do servidor private void run(String[] args) throws StockServerOpenbusException { Properties props = loadProperties(); initOpenbus(args, props); IRegistryService registryService = connectWithOpenBus(props); ComponentContext context = createComponent(props); String registrationId = registerServiceOffer(registryService, context); Runtime.getRuntime().addShutdownHook(new ShutdownThread(registrationId)); Openbus.getInstance().getORB().run(); } public static void main(String[] args) { StockServerOpenbus demo = new StockServerOpenbus(); try { demo.run(args); } catch (Throwable e) { e.printStackTrace(); } } Inicializar o Openbus private void initOpenbus(String[] args, Properties props) throws StockServerOpenbusException { String host = props.getProperty("host.name"); String portString = props.getProperty("host.port"); int port = Integer.valueOf(portString); Log.setLogsLevel(Level.WARNING); Properties orbProps = new Properties(); orbProps.setProperty("org.omg.CORBA.ORBClass", "org.jacorb.orb.ORB"); orbProps.setProperty("org.omg.CORBA.ORBSingletonClass", "org.jacorb.orb.ORBSingleton"); Openbus bus = Openbus.getInstance(); try { bus.init(args, orbProps, host, port); } catch (Exception e) { throw new StockServerOpenbusException( "Erro durante a inicialização do Openbus.", e); } } Fazer a conexão por certificado private IRegistryService connectWithOpenBus(Properties props) throws StockServerOpenbusException { String entityName = props.getProperty("entity.name"); String privateKeyFile = props.getProperty("private.key"); String acsCertificateFile = props.getProperty("acs.certificate"); try { RSAPrivateKey privateKey = CryptoUtils.readPrivateKey(privateKeyFile); X509Certificate acsCertificate = CryptoUtils.readCertificate(acsCertificateFile); Openbus bus = Openbus.getInstance(); IRegistryService registryService = bus.connect(entityName, privateKey, acsCertificate); if (registryService == null) { throw new RSUnavailableException(); } System.out.println("Stock Server conectado."); return registryService; } catch (Exception e) { ... } } Criar o componente private ComponentContext createComponent(Properties props) throws StockServerOpenbusException { Openbus bus = Openbus.getInstance(); ComponentBuilder builder = new ComponentBuilder(bus.getRootPOA(), bus.getORB()); ComponentId componentId = new ComponentId("StockSeller", (byte) 1, (byte) 0, (byte) 0, "Java"); ComponentContext context = new StockSellerContextImpl(builder, componentId); ExtendedFacetDescription[] facetDescriptions = createFacetDescriptions(props); ReceptacleDescription[] recDescriptions = createReceptacleDescriptions(); try { context = builder.newComponent(facetDescriptions, recDescriptions, componentId, context); return context; } catch (Exception e) { ... } } Criar o componente - facetas private ExtendedFacetDescription[] createFacetDescriptions(Properties props) { String stockServerFacetClass = props.getProperty("stockserver.class"); String stockExchageFacetClass = props.getProperty("stockexchange.class"); ExtendedFacetDescription[] facetDescriptions = new ExtendedFacetDescription[2]; facetDescriptions[0] = new ExtendedFacetDescription("StockServer", StockServerHelper.id(), stockServerFacetClass); facetDescriptions[1] = new ExtendedFacetDescription("StockExchange", StockExchangeHelper.id(), stockExchageFacetClass); return facetDescriptions; } Criar o componente - receptáculos private ReceptacleDescription[] createReceptacleDescriptions() { ReceptacleDescription[] recDescriptions = new ReceptacleDescription[1]; recDescriptions[0] = new ReceptacleDescription("Printer", ExchangePrinterHelper.id(), false, null); return recDescriptions; } Registrar a oferta de serviço private String registerServiceOffer(IRegistryService registryService, ComponentContext context) throws StockServerOpenbusException { org.omg.CORBA.Object obj = context.getIComponent(); IComponent component = IComponentHelper.narrow(obj); Property registrationProps[] = new Property[0]; ServiceOffer serviceOffer = new ServiceOffer(registrationProps, component); try { String registrationId = registryService.register(serviceOffer); System.out.println("Stock Server registrado."); return registrationId; } catch (Exception e) { throw new StockServerOpenbusException( "Erro ao registrar a oferta do componente SCS", e); } } Instalar o ShutdownHook Runtime.getRuntime().addShutdownHook(new ShutdownThread(registrationId)); ... private static class ShutdownThread extends Thread { private String registrationId; ShutdownThread(String registrationId) { this.registrationId = registrationId; } run() { Openbus bus = Openbus.getInstance(); IRegistryService registryService = bus.getRegistryService(); registryService.unregister(registrationId); bus.disconnect(); } } Iniciar a execução do ORB Openbus.getInstance().getORB().run(); Passo 5: Implementando o Cliente • O programa cliente se encarrega de: – inicializar o Openbus – fazer a conexão por usuário e senha Fluxo principal do cliente private void run(String[] args) throws StockClientOpenbusException { Properties props = loadProperties(); Openbus bus = initOpenbus(args, props); IRegistryService registryService = connectWithOpenBus(props); StockServer stockServer = getStockServer (registryService); System.out.println("Ações de mercado obtidas do StockServer:"); // Obtém os símbolos de todas as ações String[] stockSymbols = stockServer.getStockSymbols(); // Mostra as ações de mercado com seus respectivos valores for (int i = 0; i < stockSymbols.length; i++) { System.out.println(stockSymbols[i] + " " + stockServer.getStockValue(stockSymbols[i])); } StockExchange stockExchange = getStockExchange(registryService); // Compra uma ação if (stockSymbols.length > 0) { String first = stockSymbols[0]; System.out.println("--Compra a ação :" + first); stockExchange.buyStock(first); System.out.println("--Ação " + first + " depois da negociação: " + stockServer.getStockValue(first)); } bus.disconnect(); Conectando com usuário e senha private IRegistryService connectWithOpenBus(Properties props) throws StockClientOpenbusException { String userLogin = props.getProperty("login"); String userPassword = props.getProperty("password"); Openbus bus = Openbus.getInstance(); try { IRegistryService registryService = bus.connect(userLogin, userPassword); if (registryService == null) { throw new RSUnavailableException(); } System.out.println("Stock Client conectado."); return registryService; } catch (Exception e) { throw new StockClientOpenbusException( "Erro ao fazer a conexão com o Openbus", e); } } Procurando pelas facetas private StockServer getStockServer(IRegistryService registryService) { ServiceOffer[] servicesOffers = registryService.find(new String[] { "StockServer”}); ServiceOffer serviceOffer = servicesOffers[0]; IComponent component = serviceOffer.member; org.omg.CORBA.Object stockServerObject = component.getFacetByName("StockServer"); return StockServerHelper.narrow(stockServerObject); } private StockExchange getStockExchange(IRegistryService registryService) { ServiceOffer[] servicesOffers = registryService.find(new String[] { "StockServer" }); ServiceOffer serviceOffer = servicesOffers[0]; IComponent component = serviceOffer.member; org.omg.CORBA.Object stockExchangeObject = component.getFacetByName("StockExchange"); return StockExchangeHelper.narrow(stockExchangeObject); }