sábado, 1 de setembro de 2012

Desenvolvendo bundles OSGi


INTRODUÇÃO

Nesse artigo explicaremos a construção de bundles OSGi que criam e usam serviços. Para isso, vamos usar o IDE Eclipse 3.7 (Indigo) e a implementação OSGi Eclipse Equinox.
A tecnologia OSGi preenche o buraco da falta de modularidade nos jars da linguagem Java e também, prove algumas características:

  • Instalação, inicio, finalização, desinstalação de modo dinâmico, sem necessitar parar a aplicação Java. Isso é uma característica muito usada em servidores de aplicação como JBoss AS, Glassfish, Weblogic e outros. Mas, uma aplicação Java qualquer pode usar esse mecanismo, provido pelo framework OSGi. Assim, podemos desenvolver uma aplicação desktop que pode de maneira dinâmica (sem reinício, parada), instalar e desinstalar componentes (por exemplo).
  • Isolamento dos componentes (bundles), pois cada bundle possui o seu Classloader e se algum bundle “morrer”, os outros bundles permanecem ativos.
  • Controle de visibilidade de pacotes, pois com os uso dos jars, todas as classes públicas ficam visíveis no classpath da aplicação, mas num bundle OSGi, podemos restringir a visibilidade das classes, de maneira que exportamos apenas as classes que poderão ser usadas por outros bundles.
  • Criação e uso de serviços sobre a VM, podemos ter um bundle que cria o serviço, com um determinado nome e do outro lado, teremos n bundles chamando e executando o serviço definido no bundle original. Podemos monitorar as alterações nos serviços no contexto da aplicação, através do uso de ouvintes (listeners) que são chamados quando algum serviço é alterado.
  • Versionamento, podemos ter bundles com os mesmos nomes mas em versões diferentes, algo que com o uso de jars simples, não podemos ter a mesma classe definida em dois jars diferentes e no mesmo classpath, pois no momento da busca da classe pelo Classloader, a primeira classe encontrada é que será usada. No OSGi, temos o controle de versão, então, podemos definir quais pacotes de tais versões queremos importar.


CONSTRUÇÃO DO EXEMPLO DE UM TRADUTOR

Vamos criar um sistema que traduz palavras para um idioma de destino, a ideia é ter um bundle que define a interface, vamos chamar de “TradutorCore”, e para cada idioma de destino, vamos criar os bundles “TradutorEnglish” para implementar a interface para traduzir palavras para o idioma inglês e “TradutorSpanish” para implementar a interface para traduzir palavras para o idioma espanhol. E um bundle para cliente para consumir os serviços criados, vamos chamar de “TradutorCliente”.



BUNDLE “TradutorCore”

Nas figuras a seguir, será mostrado passo a passo o processo de criação de bundle OSGi no IDE Eclipse (Versão indigo 3.7.2).


































BUNDLE “TradutorEnglish”

Nas figuras a seguir, será mostrado o processo para criar o bundle que implementará o serviço de tradução (interface ITradutor). Como o processo de criação de bundle já foi explicado detalhadamente no bundle “TradutorCore” e também, da mesma maneira que criamos o bundle anterior, podemos criar esse, então nas figuras a seguir serão mostradas apenas os passos distintos e com algumas observações.
















BUNDLE “TradutorCliente”

Nas figuras a seguir, será mostrado o processo para criar o bundle que consumirá os serviços registrados no framework OSGi pelas implementações “TradutorEnglish” e outras que existerem no momento da chamada.









Código do Activator.java do bundle OSGi “TradutorCliente”.

package tradutorcliente;

import java.util.Calendar;
import java.util.List;

import org.osgi.framework.BundleActivator;
import org.osgi.framework.BundleContext;
import org.osgi.framework.ServiceEvent;
import org.osgi.framework.ServiceListener;
import org.osgi.framework.ServiceReference;

import tradutorcore.ITradutor;

public class Activator implements BundleActivator {
private BundleContext context;
private ServiceListener listener;

public void start(BundleContext bundleContext) throws Exception {
System.out.println("Bundle TradutorCliente - INICIADO");
context = bundleContext;
listener = new ServiceClientListener(this);
context.addServiceListener(listener);
execute();
}

public void stop(BundleContext bundleContext) throws Exception {
System.out.println("Bundle TradutorCliente - PARADO");

context.removeServiceListener(listener);
context = null;
}

private void execute() throws Exception {
ServiceReference<Itradutor> tradutores[] =
(ServiceReference<Itradutor>[]) context
.getServiceReferences(ITradutor.class.getName(), "("
+ ITradutor.LANGUAGE + "=*)");

if (tradutores != null) {
for (int i = 0; i < tradutores.length; i++) {
if (tradutores[i] != null) {

ITradutor t = context.getService(tradutores[i]);

if (t != null) {
List words = t.translate("Qualquer coisa "
+ Calendar.getInstance().getTime());

System.out.println("Traduções: " + words);
}
}
}
}

System.out
.println("Bundle TradutorCliente - Tradutores: " + tradutores);
}

private static class ServiceClientListener implements ServiceListener {
private Activator ac;

public ServiceClientListener(Activator ac) {
this.ac = ac;
}

@Override
public void serviceChanged(ServiceEvent arg0) {
if (ServiceEvent.MODIFIED == arg0.getType()) {
System.out.println("Serviço modificado: " + arg0.getSource());

} else if (ServiceEvent.REGISTERED == arg0.getType()) {
System.out.println("Serviço registrado: " + arg0.getSource());

} else if (ServiceEvent.UNREGISTERING == arg0.getType()) {
System.out
.println("Serviço desregistrado: " + arg0.getSource());

} else if (ServiceEvent.MODIFIED_ENDMATCH == arg0.getType()) {
System.out.println("Serviço modificado endmatch: "
+ arg0.getSource());

} else {
System.out.println("Serviço outros eventos: "
+ arg0.getSource());
}

try {
ac.execute();

} catch (Exception e) {
e.printStackTrace();
}
}
}
}


RODANDO OS BUNDLES NO IDE ECLIPSE

O próximo passo é executar os bundles criados e mostrar os serviços sendo registrados, chamados e desregistrados. Para isso, precisamos executar os bundles em cima de alguma implementação do framework OSGi como Eclipse Equinox, JBoss AS 7.x, Apache Felix e outros. E por sua vez, esses frameworks rodam em cima de JVM. Nesse artigo mostraremos apenas a execução desses bundles dentro da infraestrutura de desenvolvimento providenciada pela IDE Eclipse, conforme mostra as figuras a seguir.


















CONCLUSÃO

Nesse artigo mostramos a construção e execução de bundles OSGi sobre o framework OSGi Eclipse Equinox. Nesses bundles, desenhamos uma estrutura simples de uso e consumo de serviços através do uso do mecanismo de serviços da API da especificação OSGi.
Com isso, promovemos o isolamento da implementação da interface com o uso do objeto que implementa a interface, pois o cliente que invoca métodos (serviços) da interface não necessita conhecer a classe que implementa essa interface. Pois com o uso do OSGi, teríamos um bundle para definir as interfaces, outros para implementá-las como serviços e outros bundles para chamar essas implementações, mas sem conhecer a classe que implementa essas interfaces, promovendo maior desacoplamento no código. E também, não ficamos presos a uma implementação particular do framework OSGi, pois qualquer framework OSGi pode ser usado para executar os bundles descritos nesse artigo.


REFERÊNCIAS




Nenhum comentário:

Postar um comentário