O termo “Open Services Gateway Initiative” (OSGi), também conhecido como Sistema Modular e Dinâmico para Java, define uma arquitetura para o desenvolvimento e implantação de aplicações modulares e de bibliotecas. Através do entendimento conceitual e do que realmente é o OSGi é possível construir aplicações simples usando implementações como a Eclipse OSGi, Equinox e Apache Felix, assim como quebrar a aplicação em vários módulos e, portanto, facilmente gerenciar cruzamentos independentes entre eles.

Semelhante às especificações Java Servlet e EJB, a OSGi define duas coisas: um conjunto de serviços que um container OSGi deve implementar e um contrato entre o container e a aplicação. Isso significa que desenvolver softwares na plataforma OSGI significa primeiramente construir o seu aplicativo usando a API do OSGi e depois implantá-lo em um container OSGi. Do ponto de vista de um programador, a OSGi oferece algumas vantagens:

  • Você pode instalar, desinstalar, iniciar e parar diferentes módulos do seu aplicativo dinamicamente, sem precisar recomeçar o container.
  • Seu aplicativo pode ter mais de uma versão de um módulo particular funcionando e executando ao mesmo tempo.
  • A OSGi garante uma ótima infraestrutura para desenvolvimento de aplicativos com orientados a serviços, assim como integrados, aplicativos de internet móvel e APPs para internet ricos.

Com a utilização de containers servlet para a criação de aplicativos Web e containers EJB para a construção de aplicativos transacionais, você pode estar se perguntando nesse momento: por que eu precisaria de outro tipo de container? A resposta mais objetiva é que os containers OSGi são destinados especificamente para o desenvolvimento de aplicativos Java complexos que pretendem dividir-se em módulos.

A OSGi em aplicações empresariais

Os trabalhos em cima da especificação OSGi foram iniciados em março de 1999 pela OSGi Alliance. O principal objetivo era criar uma especificação que permitisse a entrega de serviços gerenciados para redes e dispositivos locais. A ideia básica é que, uma vez que seja adicionado um OSGi Service Plataform em um dispositivo de rede (incorporado, bem como servidores), há a capacidade de gerenciar o ciclo de vida de componentes de software de qualquer lugar na rede. Os componentes de software podem ser instalados, atualizados ou removidos em tempo real sem ter que interromper a operação do dispositivo.

Por anos, a tecnologia OSGi se desenvolveu nos sistemas embarcados e no mercado de dispositivo móveis. Agora, graças ao Eclipse, a OSGi está emergindo como uma tecnologia viável e valiosa para o desenvolvimento empresarial.

Em 2003, a equipe de desenvolvimento Eclipse começou a procurar formas de tornar essa plataforma mais dinâmica e de aumentar a modularidade do conjunto de ferramentas. A princípio, a equipe se estabeleceu utilizando a estrutura OSGi como um modelo de componentes de tempo de execução. O Eclipse 3.0, lançado em junho de 2004, foi a primeira versão do Eclipse baseado em OSGi.

Quase todos os servidores de aplicativos corporativos apoiam ou ao menos pretendem apoiar a OSGi. O Spring framework também suporta OSGi, através do projeto de módulos dinâmicos dos serviços de plataforma OSGi, que fornece uma infraestrutura para facilitar a utilização do OSGi no desenvolvimento de aplicativos corporativos Java baseado em Spring.

Containers OSGi Open source

Do ponto de vista de um administrador de empresas, o container tem uma “sacada” tão simples que é possível facilmente inserir a mesma em um aplicativo corporativo. Por exemplo, digamos que você esteja desenvolvendo um aplicativo web complexo. Você quer quebrar o aplicativo em vários módulos: um para a camada de visão, outra para a camada de DAO e um terceiro para a camada de acesso de dados. Usando um container OSGi integrado para gerenciar o cruzamento desses módulos, será possível atualizar a sua camada DAO sem reiniciar o aplicativo.

Desde que o aplicativo seja compatível com a plataforma OSGi, ele será capaz de rodar em qualquer container compatível. Atualmente existem três principais containers OSGi:

  • Equinox é a implementação de referência para a estrutura do OSGI Service Plataform Release 4. Ele é o ambiente de execução modular no coração do eclipse IDE, e implementa todas as funcionalidades necessárias e opcionais para a especificação OSGi R4.
  • Knopflerfish é uma implementação das especificações OSGi R3 e OSGi R4. O Knopflerfish 2 implementa todas as características obrigatórias e algumas das características opcionais definidas na especificação R4.
  • Apache Felix é o container OSGi Open Source da Apache Software Foundation. Até o momento deste artigo, não foi constatado que ele é totalmente compatível com a especificação OSGi R4.

Alô Mundo

Em OSGi, os softwares são distribuídos na forma de pacotes. Um pacote consiste de classes Java e outros recursos que oferece funções para o proprietário do dispositivo, bem como providencia serviços e pacotes para outros pacotes. O Eclipse oferece um excelente apoio para o desenvolvimento de arquivos de propriedade OSGi. Não só fornece assistentes para a criação de pacotes OSGi, como também tem um container Equinox OSGi embutido que você pode utilizar para executar e depurar plug-ins OSGi. Perceba que todo plug-in Eclipse é essencialmente um arquivo de propriedade OSGi com algum adicional de código específico Eclipse. Eclipse também permite que você construa standard-compliant arquivos de propriedade OSGi sem código específico do Eclipse. Vejamos então como desenvolver um pacote “Alô Mundo” usando o Eclipse IDE.

Criando o pacote

Siga os passos abaixo para criar o pacote “Alô Mundo’ usando a OSGi e o Eclipse.

  1. No Eclipse, clique em File --> New --> Project. Um novo projeto irá abrir.
  2. No novo projeto, selecione Plug-in Projecte clique em Next. O Plug-in Project irá abrir.
  3. No Plug-in Project, coloque as seguintes informações:
    - Nome do Projeto:br.edu.devmedia.exemplo.AloMundo
    -Plataforma de Destino: OSGi framework --> Standard
  4. Use os valores restantes para as demais entradas e clique em Next. O Plug-in “Context” vai abrir.
  5. Selecione os valores padrões para o Plug-in Context e clique em Next.
  6. Na caixa de diálogo de Templates, você irá encontrar somente uma entrada de Templates Disponíveis. Selecione e clique em Finish.

O Eclipse vai demorar alguns segundos para gerar um template de código para o arquivo de propriedades “Alô Mundo”. Ele irá cria também dois arquivos: Activator.java e MANIFEST.MF. Vamos analisar os dois mais a fundo.

Activator.java

Seu Activator.javadeve ficar parecido com a demonstração da Listagem 1.

Listagem 1. Representação da classe gerada Activator.java

package br.edu.devmedia.exemplo.alomundo;
   
  import org.osgi.framework.BundleActivator;
  import org.osgi.framework.BundleContext;
   
  public class Activator implements BundleActivator {
   
      public void start(BundleContext context) throws Exception {
          System.out.println("Alô Mundo");
      }
       
      public void stop(BundleContext context) throws Exception {
          System.out.println("Adeus Mundo");
      }
  }

Se seu arquivo de propriedade precisar notificar o momento de iniciar ou parar, então você deve criar uma classe implementando a interface do BundleActivator. Veja os passos abaixo:

  • A classe BundleActivator deve ter um construtor público sem parâmetros. O framework OSGi pode criar um BundleActivator chamando Class.newInstance().
  • O container irá chamar o método start() da sua classe Activator para iniciar o pacote. O pacote pode aproveitar essa oportunidade para executar a inicialização de recursos, tais como a obtenção de uma conexão de banco de dados para uso futuro. O método start() tem um argumento, o objeto BundleContext. Esse objeto permite que os pacotes interajam com o framework providenciando o acesso a informação do container OSGi relacionado. Se uma exceção é lançada para um pacote em particular, o container vai marcar o pacote como “parado” e não vai colocá-lo em serviço.
  • O container irá chamar o método stop() da classe Activator para informar que está encerrando o pacote em questão. Você pode usar essa oportunidade para realizar tarefas de limpeza, como a liberação de uma conexão de dados.

Uma vez que a sua classe Activator estiver pronta, você deve relatar o seu nome completo ao container usando o seu arquivo MANIFEST.MF.

O arquivo MANIFEST.MF atua como descritor de implementação para o seu pacote. O formato desse arquivo é o mesmo que o de um arquivo JAR normal, de modo que é constituído por um conjunto de cabeçalhos com valores. A especificação OSGi define um conjunto de cabeçalhos que você pode usar para descrever seu pacote para o container OSGi. O arquivo MANIFEST.MF para seu pacote Alô Mundo deve ficar como mostrado na Listagem 2.

Listagem 2. Arquivo Manifest para o pacote Alo Mundo


  Manifest-Version: 1.0
  Bundle-ManifestVersion: 2
  Bundle-Name: AloMundo Plug-in
  Bundle-SymbolicName: br.edu.devmedia.exemplo.AloMundo
  Bundle-Version: 1.0.0
  Bundle-Activator: br.edu.devmedia.exemplo.alomundo.Activator
  Bundle-Vendor: DEVMEDIA
  Bundle-Localization: plugin
  Import-Package: org.osgi.framework;version="1.3.0"

Vamos dar uma olhada para que serve cada um destes cabeçalhos:

  • Bundle-ManifestVersion: informa ao container OSGi que este pacote segue as regras da especificação OSGi. O valor número 2 significa que o pacote é compatível com a especificação OSGi Release 4; o valor número 1 significa que é compatível com a versão 3 ou anterior.
  • Bundle-Name: define um nome legível e curto para o pacote.
  • Bundle-SymbolicName: especifica um único nome, não localizável para o pacote. Este é o nome que você vai usar ao se referir a um determinado conjunto de outros pacotes.
  • Bundle-Version: especifica a versão do arquivo de propriedade.
  • Bundle-Activator: especifica o nome da classe ouvinte opcional para ser notificada acerca dos eventos de início e fim do pacote. Na Listagem 2, o valor deste cabeçalho é br.edu.devmedia.exemplo.alomundo.Activator.
  • Bundle-Vendor: contém uma descrição legível do fornecedor do pacote.
  • Bundle-Localization: contém a localização do pacote e onde os seus arquivos podem ser encontrados. O pacote Alô Mundo não contém qualquer localização específica de arquivos, mas o eclipse IDE ainda gera este cabeçalho.
  • Import-Package: define pacotes importados para o pacote principal. Você aprenderá mais sobre isso quando discutirmos gerenciamento de dependência, no final do artigo.
Como o pacote Alô Mundo está pronto, então vamos executá-lo para ver a saída.

Executando o pacote

Como mencionado anteriormente, o Eclipse IDE teria um container Equinox OSGi incorporado, que você pode usar para executar ou depurar pacotes OSGi. Siga essas etapas para executar o pacote Alo Mundo.

  1. Clique em Run --> Run.
  2. O Eclipse irá abrir uma caixa de diálogo chamada “Criar, gerenciar e executar a configuração.” Nessa caixa de diálogo, um duplo clique no botão Framework Equinox OSGi Eclipse que irá abrir uma caixa de configuração.
  3. Lá, mude o nome para Alo Mundo Bundle.
  4. Você vai perceber que nos Plug-ins da seção abaixo do plug-in Workspace há uma entrada para:br.edu.devmedia.exemplo.AloMundo que estará checada. Sob a plataforma de destino, certifique-se de que a caixa de seleção ao lado do org.eclipse.osgi também esteja checada.
  5. Agora clique no botão Executar. Você deverá ver uma mensagem "Alô Mundo" visível no console da IDE. Note que o Eclipse realmente abre o console OSGi na tela.

O console OSGi

O Console OSGi é uma interface de linha de comando para o container OSGi. Ele permite que você faça coisas como iniciar, parar, instalar, atualizar ou excluir arquivos de propriedade. No seu Eclipse IDE, clique na exibição do console para dar o foco para esse comando, em seguida, clique em Inserir, e você obterá um prompt OSGi como exibido na Figura 1.

Representação do Console do OSGi
Figura 1. Representação do Console do OSGi

Aqui estão alguns dos comandos mais utilizados no OSGi, que você pode usar para interagir com o container OSGi:

  • ss:exibe uma lista de arquivos de propriedade instalados com o status de cada um deles. Ele irá exibir o ID, nome e status do arquivo de propriedade.
  • start <bundleid>:inicia o pacote.
  • stop <bundleid>:para o pacote.
  • update <bundleid>:atualiza o pacote com o novo arquivo JAR.
  • install <bundleURL>:instala o novo pacote no OSGi Container.
  • uninstall <bundleid>:desinstala pacotes do OSGi Container.

Note que estes comandos são definidos na especificação OSGi para que você possa usá-los para interagir com quaisquer dos containers OSGi.

Gerenciamento de dependência

A especificação OSGi permite que você quebre a sua aplicação em vários módulos e, em seguida, gerencie suas dependências em cada um. Isso é feito através da adição de um escopo de pacote. Normalmente, nenhuma classe em um pacote é visível de qualquer outro, elas seguem as regras normais da linguagem Java. Então, o que você faz se você quiser acessar as classes de um pacote para outro? A solução é exportar pacotes do arquivo fonte e, em seguida, importá-los para o arquivo de destino. Logo, criemos o arquivo br.edu.devmedia.exemplo.AloMundoService, que irá exportar um pacote. Depois vamos importar o pacote para o nosso arquivo br.edu.devmedia.exemplo.AloMundo.

Exportando um Pacote

Vamos começar criando o arquivo br.edu.devmedia.exemplo.AloMundoService e exportando o pacote para ele. Para criar o pacote e exportá-lo é necessário criar o arquivo br.edu.devmedia.exemplo.AloMundoService seguindo os mesmos passos utilizados para criar o br.edu.devmedia.exemplo.AloMundo na seção anterior. Em seguida, no arquivo HelloService crie a interface br.edu.devmedia.exemplo.AloMundoService.java como na Listagem 3.

Listagem 3. Classe AloMundoService.java

public interface AloMundoService {
       public String dizerAlo();
  }

Agora crie a classe br.edu.devmedia.exemplo.AloMundoServiceImpl.java implementando a interface AloMundoService como na Listagem 4.

Listagem 4. Representação da classe AloMundoServiceImpl.java


  public class AloMundoServiceImpl implements AloMundoService {
       public String dizerAlo() {
           System.out.println("AloMundoServiceImpl.dizerAlo()");
           return "Dizer Alô!";
      }
  }

Abra o MANIFEST.MF do pacote AloMundoService no editor Manifest do Eclipse e vá para a guia Runtime. Na seção de pacotes exportados, clique em Adicionar e selecione o pacote br.edu.devmedia.exemplo.service. O arquivo MANIFEST.MF para o pacote AloMundoService deverá ser parecido com o da Listagem 5.

Listagem 5. Arquivo MANIFEST.MF para o pacote AloMundoService


  Manifest-Version: 1.0
  Bundle-ManifestVersion: 2
  Bundle-Name: HelloService Plug-in
  Bundle-SymbolicName: br.edu.devmedia.exemplo.HelloService
  Bundle-Version: 1.0.0
  Bundle-Vendor: DEVMEDIA
  Bundle-Localization: plugin
  Export-Package: br.edu.devmedia.exemplo.service
  Import-Package: org.osgi.framework;version="1.3.0"

Como pode ver, o arquivo MANIFEST.MF para o pacote AloMundoService parece muito similar ao do AloMundo em suas propriedades. A única diferença é que o arquivo MANIFEST.MF tem uma propriedade a mais, a Export-Package, que valida o pacote br.edu.devmedia.exemplo.service.

O Export-Package informa ao container OSGi que as classes contidas no pacote br.edu.devmedia.exemplo.service para o pacote AloMundoService podem ser acessadas de fora do mesmo. Perceba que no código de exemplo, expomos a interface AloMundoService, mas não a classe implementadora AloMundoServiceImpl.

Importando o pacote

O próximo passo é atualizar o arquivo AloMundo para importar o pacote br.edu.devmedia.exemplo.service. Para isso, no arquivo br.edu.devmedia.exemplo.AloMundo abra o arquivo MANIFEST.MF no editor Manifest do plug-in. Agora vá para a guia Dependências e depois para Pacotes Importados. Adicione br.edu.devmedia.exemplo.service como valor dos Imported Packages (“Pacotes Importados”). O arquivo MANIFEST.MF para o seu arquivo AloMundo deve parecer com a Listagem 6.

Listagem 6. Manifest para a atualização do arquivo AloMundo


  Manifest-Version: 1.0
  Bundle-ManifestVersion: 2
  Bundle-Name: AloMundo Plug-in
  Bundle-SymbolicName: br.edu.devmedia.exemplo.AloMundo
  Bundle-Version: 1.0.0
  Bundle-Activator: br.edu.devmedia.exemplo.alomundo.Activator
  Bundle-Vendor: DEVMEDIA
  Bundle-Localization: plugin
  Import-Package: br.edu.devmedia.exemplo.service,
  org.osgi.framework;version="1.3.0"
  

Como pode ver o valor do Import-Package é uma lista separada por vírgula de pacotes que se de importar. No código de exemplo o pacote AloMundo importa dois pacotes br.edu.devmedia.exemplo.service e org.osgi.framework.

O pacote org.osgi.framework contém classes do framework OSGi como BundleContext e BundleActivator, que são usadas pela classe Activator.java do pacote AloMundo.

Agora abra a classe br.edu.devmedia.exemplo.alomundo.Activator.java no editor Eclipse Java. Você vai perceber que o acesso à interface AloMundoService está agora disponível, mas não o acesso à classe AloMundoServiceImpl. Isso acontece porque o pacote AloMundoService exporta (e o pacote AloMundo importa) o pacote br.edu.devmedia.exemplo.service.

A classe AloMundoService implementa uma classe interna do pacote AloMundoService e nenhum outro arquivo pode acessá-lo.

Class-level scope

Se você está tentando rodar o exemplo agora não irá receber um "Alô Mundo" como resultado no seu console do Eclipse. Se você tentar rodar Activator.java para acessar AloMundoServiceImpl.java e compilar com o compilador javac irá conseguir. Se você tentar executar o arquivo de propriedade em um container OSGi, entretanto, será lançada uma exceção.

Como o container OSGi é capaz de esconder algumas classes do arquivo .jar enquanto outras estão visíveis? A resposta é que o container OSGi cria uma classe diferente para cada pacote. O pacote pode, portanto, acessar as classes de:

  • Boot classpath: Contém os pacotesjava.*
  • Framework classpath: Normalmente tem um carregador de classes separado para as classes de implementação de enquadramento, bem como principais classes de interface de serviço.
  • Bundle space: Consiste no arquivo JAR que está associado com o pacote mais quaisquer arquivos JARs adicionais que estão intimamente ligados ao pacote, como fragmentos.
  • Imported packages: Por exemplo, o pacoteAloMundo importa o pacote br.edu.devmedia.exemplo.service, logo ele pode acessar as classes deste pacote.
  • O bundle-level scope é um poderoso recurso que permite que você possa mudar com segurança a classe AloMundoServiceImpl.java sem se preocupar com a quebra do código dependente.

Links Úteis

  • Django REST: Criando uma API web:
    Neste curso veremos como desenvolver uma API RESTful utilizando os frameworks Django e Django REST Framework. Para isso, será implementado um CRUD de vagas com os recursos de validação e paginação dos registros.
  • JavaScript Substring: Manipulando strings:
    Aprenda neste artigo a utilizar o método substring() para manipulação de strings em JavaScript.
  • O que é React?:
    Neste curso aprenderemos o que é o React, um dos frameworks JavaScript que mais está em alta no mercado atualmente. Desenvolvido pelo Facebook, o React utiliza o conceito de componentes para criar aplicações com interfaces ricas, mantendo o isolamento entre as partes que compõem as páginas.

Saiba mais sobre OSGi ;)

  • OSGi com Spring Dynamic Modules:
    O artigo trata do desenvolvimento de aplicações modulares desktop com OSGi utilizando o framework Spring Dynamic Modules e a plataforma OSGi Equinox.
  • Modularização dinâmica em Java com OSGi:
    Conheça os benefícios que uma arquitetura modular em OSGi pode oferecer para suas aplicações.
  • Modularidade em Java:
    O artigo aborda o framework OSGi e sua plataforma de serviços, trazendo modularidade para a plataforma Java. A maioria dos conceitos envolvendo o uso de módulos dentro da plataforma OSGi é apresentada no decorrer do artigo com exemplos práticos e comparações ao desenvolvimento Java “tradicional”.