Introdução ao OSGi
Neste artigo veremos os conceitos mais básicos de criação e manuseio das classes responsáveis por gerenciar todo o escopo executável do OSGi.
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.
- No Eclipse, clique em File --> New --> Project. Um novo projeto irá abrir.
- No novo projeto, selecione Plug-in Projecte clique em Next. O Plug-in Project irá abrir.
- No Plug-in
Project, coloque as seguintes informações:
- Nome do Projeto:br.edu.devmedia.exemplo.AloMundo
-Plataforma de Destino: OSGi framework --> Standard - Use os valores restantes para as demais entradas e clique em Next. O Plug-in “Context” vai abrir.
- Selecione os valores padrões para o Plug-in Context e clique em Next.
- 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.
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.
- Clique em Run --> Run.
- 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.
- Lá, mude o nome para Alo Mundo Bundle.
- 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.
- 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.
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”.
Artigos relacionados
-
Artigo
-
Artigo
-
Artigo
-
Artigo
-
Vídeo