sexta-feira, 5 de outubro de 2012

Auto-deploy com Eclipse Equinox e Apache Felix File Install


INTRODUÇÃO

Nesse artigo vamos mostrar como integrar o framework OSGi Eclipse Equinox com o bundle OSGi Apache Felix Install. Com o uso do File Install, podemos configurar o recurso de auto-deploy de maneira que ao adicionarmos e / ou removermos algum bundle OSGi, o plugin será automaticamente instalado ou desinstalado. E também, podemos configurar se o plugin instalado deve ser automaticamente iniciado. Sem o recurso do auto-deploy, teremos que usar a API do framework OSGi de maneira a instalarmos os nossos bundles explicitamente e não basta adicionar / remover bundle OSGi de algum diretório, por exemplo. Com o auto-deploy, teremos o mesmo comportamento de implantar e desimplantar bundles OSGi igualmente aos servidores de aplicações Java EE (JBoss AS, Glassfish, WebLogic, etc) os quais adicionamos arquivos “war”, “ear” para implantar uma aplicação web ou Java EE, sem a necessidade de usar a API do servidor de aplicação explicitamente. E consequentemente, esses programas (servidores de aplicação e outros) que possuam esse recurso de auto-deploy, se encarregará da instalação / desintalação, conforme arquivo de deploy (implantação) colocado (processo de deploy) ou retirado (processo de undeploy) do diretório.



CONFIGURAÇÃO DO DIRETÓRIO DO ECLIPSE EQUINOX

Primeiramente, temos criar uma estrutura de diretórios para poder rodar o Eclipse Equinox, para isso, monte essa estrutura conforme mostra a figura a seguir.




O diretório de auto-deploy será o “deploy” dentro do diretório “EquinoxApplication” que será o diretório do Equinox. O arquivo “org.eclipse.osgi_3.7.0.v20110613.jar”é encontrado dentro da pasta “plugins” do IDE Eclipse Indigo ou pode-se baixar somente o Eclipse Equinox do site (http://download.eclipse.org/equinox/).
O arquivo “org.apache.felix.fileinstall-3.2.4.jar” foi obtido no site do projeto Apache Felix File Install (http://felix.apache.org/site/downloads.cgi). O diretório “configuration” conterá as configurações do projeto, nesse exemplo, teremos o arquivo de inicialização “config.ini”o qual será mostrado na figura a seguir.




Na próxima figura, será mostrado a execução do framework OSGi Eclipse Equinox e também, os bundles instalados. Como no arquivo “config.ini” configuramos que o bundle do Apache Felix File Install para iniciar automaticamente, teremos 2 bundles ativos, conforme mostra a figura seguir.




Comando usado:

java -jar org.eclipse.osgi_3.7.0.v20110613.jar -console

Para realizar o auto-deploy, basta colocar os bundles OSGi dentro do diretório de deploy configurado anteriormente (no arquivo “config.ini”). Nas figuras a seguir será mostrado um exemplo cujo bundle OSGi foi criado no artigo (http://www.josepojr.com/2012/09/desenvolvendo-bundles-osgi.html) desse mesmo site.








CONCLUSÃO

Mostramos de maneira simples como configurar o auto-deploy em frameworks OSGi que não possuem esse suporte ou se existe, é muito complicado de configurar e usar. Com isso, temos o auto-deploy dentro do Equinox com poucas configurações e de maneira independente, no sentido de não estarmos presos as configurações de “plugins”do Equinox e sim, mantemos as nossas configurações baseadas na especificação OSGi.


REFERÊNCIAS







quinta-feira, 27 de setembro de 2012

Auto-deploy de bundles OSGi no JBoss AS 7


INTRODUÇÃO

Nesse artigo demostraremos como deve ser feito o deploy de bundles OSGi no servidor de aplicações JBOSS AS 7.1. Esse servidor na versão 7.x permite o auto deploy de bundles OSGi na revisão 4.1. Consequentemente, podemos desenvolver aplicações OSGi e fazer as mesmas serem executadas no JBoss AS 7.1 que passa a atuar como um framework OSGi (sendo que de fato é um framework OSGi, apartir da versão 7.x).
Os bundles usados nesse artigo serão os criados no artigo (http://www.josepojr.com/2012/09/desenvolvendo-bundles-osgi.html) desse mesmo site.



CONFIGURAÇÃO DO JBOSS AS 7.1 NO IDE ECLIPSE

Primeiramente, faça o download da última versão da série 7.x do servidor JBoss, aqui (http://www.jboss.org/jbossas/downloads).
Depois disso, descompacte o arquivo zip (ou tar.gz) em algum diretório do usuário. No IDE Eclipse Indigo (versão 3.7.2) e com o JBOSS TOOLS instalado, siga os passos descritos nas figuras a seguir.



















GERAÇÃO DOS JARS (BUNDLES OSGI) PARA DEPLOY

Nas próximas figuras serão mostradas o processo de exportar o plugin (gerar arquivo jar) e sua implantação no servidor de aplicações JBoss AS 7. Também será visualizado a instalação, inicialização, finalização e desinstalação de bundles OSGi.

  















CONCLUSÃO

Mostramos como usar o servidor de aplicações JBoss AS 7 como framework OSGi.É interessante notar que poucos frameworks OSGi possuem o recurso de auto-deploy, que significa deploy (implantação) de bundles OSGi de forma automática, basta adicionar o arquivo (jar) no diretório próprio do servidor que o mesmo, detectará o arquivo e fará a instalação dos bundles OSGi encontrados. Alguns deles são o JBoss AS 7 e Apache Felix File Install que permite fazer o auto-deploy através de colocar (deploy) e tirar (undeploy) de arquivos implantáveis (unidade de deploy, nesse caso o jar) de algum diretório especifico. Outros, não tem o recurso de auto-deploy, o que significa que o bundle OSGi deve ser instalado explicitamente pelo usuário, usando comandos administrativos do framework em questão, ou programando-se outra API para fazer a instalação de acordo com o código programado.



REFERÊNCIAS










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




sábado, 7 de abril de 2012

Uso do JBoss Cache para aplicações JEE



1. INTRODUÇÃO

Nesse artigo vamos mostrar o uso da API JBoss Cache versão 3.10 apelido "Cascabel" numa aplicação JEE sobre o servidor de aplicações JBoss AS 5.1. A maior vantagem de se usar JBoss Cache reside no fato do JBoss Cache estar embutido no JBoss AS 5.1. Se for usar outra API de cache, terá que configurar todo o servidor de aplicações e com isso, correndo o risco de dar conflitos com outros jars da API do servidor JBoss. Além disso, possui uma API de fácil entendimento e uso, pois com poucos objetos e operações já estaremos tirando proveito de suas funcionalidades.


2. CONFIGURAÇÃO

Para ilustrar melhor o uso da API JBoss Cache, vamos criar um projeto EAR com o nome "CacheEAR" e outro projeto web com o nome "CacheWAR".


2.1. CRIAÇÃO DO PROJETO EAR

Para isso, vamos criar um projeto Ear (Enterprise Application) no IDE Eclipse 3.7.1 (ou pode ser outra IDE, desde que possua essa funcionalidade). Chamaremos o nosso projeto EAR de "CacheEAR". Veja nas figuras a seguir a criação do projeto EAR.




Observação

Precisa ter o JBOSS TOOLS instalado no Eclipse para criar o Runtime (Ambiente de Execução) do servidor de aplicações JBoss  5.1 (veja nas figuras a seguir).







2.2. CRIAÇÃO DO PROJETO WEB

Para isso, vamos criar um projeto web dinâmico (Que cria o arquivo WAR no JEE) no IDE Eclipse 3.7.1 (ou pode ser outra IDE, desde que possua essa funcionalidade). Chamaremos o nosso projeto web de "CacheWAR". Veja nas figuras a seguir a criação do projeto WAR.







2.3. CRIAÇÃO DO LISTENER DO CACHE


Para usar o JBoss Cache numa aplicação web da melhor maneira possível, precisamos criar um listener (ouvinte) para "escutar" o início e fim de execução de uma aplicação web. No início da aplicação web, o listener limpará o cache que ficou carregado num deploy da mesma aplicação anteriormente. Essa "limpeza" é necessária, pois se a aplicação web sofrer um redeploy, consequentemente, o novo deploy estará usando um classloader (fornecido pelo containter JEE) diferente do classloader dos objetos em cache (carregados pela mesma aplicação web no deploy antigo). Consequentemente, se a aplicação web "nova" (novo redeploy) estará com o classloader diferente dos objetos cacheados no deploy anterior, o que pode resultar na ocorrência da exceção ClassCastException. Para entender melhor a hierarquia de classloader de uma aplicação web, veja nas figuras a seguir.






Por isso temos que usar o listener (classe que implementará a interface javax.servlet.ServletContextListener) que possa limpar o cache do deploy antigo antes do início da aplicação web (que criará e usará o cache). Veja nas figuras a seguir o processo de criação do listener.





Cole o código abaixo dentro do corpo do método "void contextInitialized(ServletContextEvent arg0)" do listener criado (CacheListener).




// Toda vez que a aplicação web é iniciada, o cache apartir do caminho X
// precisa ser limpo, senão o cache pode buscar objetos carregados de
// outros

// deployers cujo classloader também será outro. Consequentemente,
// ocorrerão erros de ClassCastException ao tentar recuperar objetos do
// cache.

try {

javax.naming.Context ctx = new javax.naming.InitialContext();
org.jboss.cache.CacheManager cacheManager = (org.jboss.cache.CacheManager) ctx
.lookup("java:CacheManager");

org.jboss.cache.Cache<Object, Object> cache = cacheManager.getCache(
"standard-session-cache", true);


if (CacheStatus.INSTANTIATED.equals(cache.getCacheStatus())
|| CacheStatus.STOPPED.equals(cache.getCacheStatus())) {
cache.start();
}

org.jboss.cache.Fqn<String> f = org.jboss.cache.Fqn.fromElements("nivel1");

// Limpa cache.
cache.removeNode(f);

}  catch (Exception e) {
e.printStackTrace();
}
2.4. CRIAÇÃO DO POJO PARA SER USADO NO CACHE

Para ilustrar melhor o uso do cache, vamos criar uma classe simples java (POJO) para ser usada como objeto de cache para podermos entender melhor o uso da API JBoss Cache. Lembrando que é bom que essa classe implemente a interface java.io.Serializable para poder trafegar pela rede na aplicação web.
Veja o código a seguir:



import java.io.Serializable;

public class Pojo implements Serializable {

/**
*
*/
private static final long serialVersionUID = 5549023217127630221L;

private Long id;

public Pojo(Long id) {
this.id = id;
}

public Long getId() {
return id;
}

public void setId(Long id) {
this.id = id;
}
}



2.5. CRIAÇÃO DO SERVLET DO CACHE

Para testar o uso do cache, vamos criar um servlet que estende a classe javax.servlet.http.HttpServlet.
Esse servlet numa aplicação web é responsável por tratar as requisições web recebidas (seja no protocolo HTTP, FTP, etc) e enviar respostas as requisições (ou não). Nesse exemplo, ao enviar uma requisição para o servlet, o mesmo tentará buscar o objeto da classe Pojo (criada anteriormente) do cache. Na primeira requisição ao servlet, o objeto não existirá no cache, consequentemente, o servlet criará o objeto (da classe Pojo) e depois disso, adicionará no cache e imprimirá no console dados do objeto cacheado. Nas segundas requisições em diante, o objeto estará no cache, consequentemente, o servlet apenas imprimirá o objeto do cache, sem a necessidade da criação do objeto. Lembrando também que dependendo das configurações do JBoss Cache usado (veja no arquivo $JBOSS_HOME/server/all/deploy/cluster/jboss-cache-manager.sar/META-INF/jboss-cache-manager-jboss-beans.xml para ajuste fino do cache), o objeto cacheado tem um tempo de vida no cache, o que significa que o mesmo pode ficar no cache por um intervalo de tempo finito (definido nas configurações do JBoss Cache) e depois que esse tempo "estourou", o objeto cacheado é removido do cache. Para criar o servlet, veja nas figuras a seguir:







Abaixo temos o código para ser inserido no método "protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException" do CacheServlet criado.

try {

Context ctx = new InitialContext();
CacheManager cacheManager = (CacheManager) ctx
.lookup("java:CacheManager");

Cache<Object, Object> cache = cacheManager.getCache(
"standard-session-cache", true);


                        if (CacheStatus.INSTANTIATED.equals(cache.getCacheStatus())
|| CacheStatus.STOPPED.equals(cache.getCacheStatus())) {
cache.start();
}

Fqn<String> f = Fqn.fromElements("nivel1", "nivel2");

Pojo pojo = (Pojo) cache.get(f, new Long(10));

if (pojo == null) {
Fqn<String> afqn = Fqn.fromElements("nivel1", "nivel2");
Long id = 10l;
pojo = new Pojo(new Long(1000));

cache.put(afqn, id, pojo);

System.out.println("Adicionando objeto no cache");
} else {
System.out.println("Usando objeto no cache");
}

System.out.println(cache);
System.out.println(pojo);
} catch (Exception e) {
e.printStackTrace();
}



2.6. RESUMO DA CONFIGURAÇÃO


Abaixo estão listadas as configurações dos projetos criados. Todos os passos seguidos anteriormente já criam esses arquivos automaticamente, mas, por ventura a sua IDE usada deu algum conflito, falha que você não conseguiu criar os projetos adequadamente, então, veja as configurações abaixo:


Arquivo application.xml do projeto CacheEAR



<?xml version="1.0" encoding="UTF-8"?>
<application xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:application="http://java.sun.com/xml/ns/javaee/application_5.xsd" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/application_5.xsd" id="Application_ID" version="5">
  <display-name>CacheEAR </display-name>
  <module>
    <web>
      <web-uri>CacheWAR.war </web-uri>
      <context-root>CacheWAR </context-root>
   </web>
  </module>
</application>



Arquivo web.xml do projeto CacheWAR



<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" id="WebApp_ID" version="2.5">
  <display-name>CacheWAR</display-name>
  <listener>
    <listener-class>CacheListener</listener-class>
  </listener>
  <servlet>
    <description></description>
    <display-name>CacheServlet</display-name>
    <servlet-name>CacheServlet</servlet-name>
    <servlet-class>CacheServlet</servlet-class>
  </servlet>
  <servlet-mapping>
    <servlet-name>CacheServlet</servlet-name>
    <url-pattern>/*</url-pattern>
  </servlet-mapping>
</web-app>



Figura com a estrutura de diretórios dos dois projetos (CacheEAR e CacheWAR).




2.7. EXECUTANDO UM EXEMPLO

Abra qualquer navegador e digite a seguinte URL:

http://localhost:8080/CacheWAR/

Supondo que o servidor JBoss para aplicações web está usando a porta 8080 para receber requisições e também, estamos supondo o uso do servidor local (localhost) senão, terá que substituir o "localhost" pelo nome ou ip do servidor JBoss.

Nisso, o console do servidor JBoss mostrará uma mensagem sobre o objeto conforme figura a seguir:








Nessa primeira requisição do objeto ao cache, o mesmo não está no cache, então o servlet terá que instânciar o objeto e adicionar no cache. Agora, chamamos novamente o mesmo link (http://localhost:8080/CacheWAR/) e a mensagem mostrada sobre o objeto cacheado conforme mostra a figura a seguir:


Nota-se que o objeto instanciado anteriormente (primeira requisição do objeto ao cache) e o objeto cacheado são os mesmos objetos!! Isso mostra que o JBoss Cache guarda o objeto em cache conforme suas configurações (políticas de cache que o desenvolvedor pode alterá-las no arquivo $JBOSS_HOME/server/all/deploy/cluster/jboss-cache-manager.sar/META-INF/jboss-cache-manager-jboss-beans.xml).


3. CONCLUSÃO

O JBoss Cache permite o uso de cache de maneira rápida e fácil numa aplicação JEE usando como servidor de aplicações o JBoss AS 5.1. Embora no site do JBoss Cache cite que o projeto está em "Estado de manutenção" e que novas funcionalidades a princípio não serão incorporadas, existem muitas empresas que usam o JBoss AS 5.1 em produção e cujo custo de mudar o servidor de aplicações é proibitivo, fora o risco de desconfigurar a API padrão de caches (JBoss Cache 3.1) do servidor JBoss e configurar outra API, como a Infinispan ou Ehcache dentro do servidor JBoss.


4. REFERÊNCIAS

Download da última versão do IDE Eclipse

http://www.eclipse.org/downloads/

Download da última versão do JBOSS TOOLS

http://www.jboss.org/tools/download

JBoss Cache

http://www.jboss.org/jbosscache

http://www.ime.usp.br/~reverbel/SMA-06/Slides/seminarios/

Outras API's de cache (no Java)

http://ehcache.org/

http://www.jboss.org/infinispan