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