domingo, 4 de dezembro de 2011

Deploy de arquivo SAR no JBOSS 3.2, 4.2, 5.1 e 6.1.

O servidor de aplicações JBOSS AS nas versões 3.2, 4.2, 5.1 e 6.1 possui o suporte para deploy de arquivos SAR (Service Archive). Esses arquivos são do tipo JAR, mas com algumas diferenças:

- A presença do arquivo jboss-service.xml no diretório META-INF que por sua vez, está dentro do diretório raiz do arquivo SAR.
- A presença da extensão ".sar" ao invés de usar a extensão ".jar".

Alguns servidores JBOSS AS (mais antigos) só reconhece o arquivo SAR com a sua devida extensão ".sar". Outros servidores (mais novos) reconhece o arquivo SAR tanto com a extensão ".sar" quanto com a extensão ".jar". A seguir, listamos os servidores de aplicações e os arquivos SAR reconhecidos.


- JBOSS AS 3.2.8 - Só reconhece arquivo SAR com a extensão ".sar".
- JBOSS AS 4.2.3 - Só reconhece arquivo SAR com a extensão ".sar".
- JBOSS AS 5.1.0 - Reconhece arquivo SAR com as extensões ".jar" e ".sar".
- JBOSS AS 6.1.0 - Reconhece arquivo SAR com as extensões ".jar" e ".sar".

Conteúdo de um arquivo jboss-service.xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE server PUBLIC "-//JBoss//DTD MBean Service 3.2//EN"
"http://www.jboss.org/j2ee/dtd/jboss-service_3_2.dtd">

<server>

<!-- UUIDKeyGeneratorFactoryService -->
<mbean code="test.services.AnaliseService"
name="jboss:service=AnaliseServicesInJBOSS,type=Analise">
<depends>jboss:service=Naming </depends>
<depends>jboss:service=TransactionManager </depends>
</mbean>

</server>

Nesse arquivo temos a tag mbean dentro da tag server. Essa tag mbean define uma classe (test.services.AnaliseService) que extende a classe org.jboss.system.ServiceDynamicMBeanSupport do JAR jboss-system do diretório lib do JBOSS. Essa classe (com nome AnaliseService) que implementará todo o serviço que será oferecido ao container JBOSS quando fizer o respectivo deploy. É nessa idéia que o JBOSS AS trabalha com os arquivos SAR, para oferecer serviços ao container, de maneira o mais fracamente desacoplada possível, assim, podemos criar um serviço para fazer deploy de arquivos OSGi (por exemplo) mas sem precisar recompilar o servidor de aplicações ! Nisso, o servidor receberá novas extensões sem precisar ter o seu núcleo modificado! Isso é uma característica marcante dos servidores JBOSS AS, a extensibilidade! Pois com o tempo, nós mesmos podemos implementar serviços não existentes no JBOSS AS para as nossas aplicações. Nisso os serviços de realizar deploy de EJBs, EARs, etc são todos implementados na arquitetura dos arquivos SAR! E pelo arquivo xml jboss-service, definimos as configurações necessárias para disponibilizar os nossos serviços implementados dentro do arquivo SAR.


SERVIDOR

Agora vamos criar uma classe para implementarmos serviços que serão disponibilizados ao container do JBOSS AS. No arquivo jboss-service.xml apresentado anteriormente, definimos uma classe com o nome de "test.services.AnaliseService" então, vamos utilizar as configurações do arquivo jboss-service.xml e a seguir, mostraremos a implementação dessa classe.

//--------------------

package test.services;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.List;

import javax.naming.Context;
import javax.naming.InitialContext;

import org.jboss.system.ServiceDynamicMBeanSupport;

public class AnaliseService extends ServiceDynamicMBeanSupport implements
Serializable {

     /**
      *
      */
      private static final long serialVersionUID = -4359452770360595777L;

      public List test(Object... objects) {
            // TESTAR CHAMADA DO SERVIÇO ATRAVÉS DO EJB.
           // TODO

           final List result = new ArrayList();

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

                      result.add(objects[i].toString()); 
                 }  
            } 


            System.out.println("test - Entrou aki - " + this.getClass().getName() + " - " + Calendar.getInstance().getTime()); 


            return result; 
      } 


      @Override
      protected void startService() throws Exception { 
            System.out.println("StartService [INICIO] - Entrou aki - " + this.getClass().getName() + " - " + Calendar.getInstance().getTime());
            // ACESSAR API DO CONTAINER JBOSS AS
            // COLOCAR LISTENER PARA PEGAR OS DEPLOYERS
            // OBTER OS DEPLOYERS. ASSIM PODEMOS CRIAR UMA IMPLEMENTAÇÃO
            // PARA TRATAR EJBS, ETC.
            // TODO
       
           try {
               Context ctx = new InitialContext();
               ctx.rebind("AnaliseServiceName", this);

           } catch (Exception e) {
              log.error("Caught exception during startService()", e);
           }

           System.out.println("StartService [FIM] - Entrou aki - " + this.getClass().getName() + " - " + Calendar.getInstance().getTime());
      }  
     
      @Override protected void stopService() throws Exception {
          System.out.println("StopService [INICIO] - Entrou aki - " + this.getClass().getName() + " - " + Calendar.getInstance().getTime());

          try {
             Context ctx = new InitialContext();
             ctx.unbind("AnaliseServiceName");

         } catch (Exception e) {
             log.error("Caught exception during stopService()", e);
         }
     
         System.out.println("StopService [FIM] - Entrou aki - " + this.getClass().getName() + " - " + Calendar.getInstance().getTime());
      }
}

 //--------------------




Note que essa classe implementa a interface java.io.Serializable para poder disponibilizar os nossos serviços para outros clientes remotamente (aconselhável, mas não é obrigatório). Nessa classe temos os métodos "startService" e "stopService" que são chamados quando o deploy do arquivo SAR é iniciado ou finalizado. É aconselhável colocar as implementações para realizarem tarefas antes da disponibilização dos serviços (deploy) ou na finalização de disponibilização dos serviços (undeploy). Depois disso, vamos criar um JAR contendo os seguintes diretórios e arquivos: - META-INF/jboss-service.xml - test.services/AnaliseService.java Para criar o JAR, vamos utilizar o IDE Eclipse, para isso, apenas crie um projeto JAVA, e no diretório das fontes (geralmente com o nome de "src"), criamos o pacote "test.services" contendo a classe AnaliseService. E na raiz do projeto, criamos o diretório "META-INF" contendo o arquivo jboss-service.xml. Além disso, precisa-se usar as dependências do JBOSS para que possa "reconhecer" a classe org.jboss.system.ServiceDynamicMBeanSupport. No eclipse basta ir em propriedades do projeto JAVA (selecionar projeto e clicar com o botão direito e selecionar o item de menu "properties"), procure a propriedade "Java Build Path", aba "Libraries" e clique no botão "add Library...". Depois disso, selecione o tipo de biblioteca como "server runtime" e selecione as bibliotecas do tipo "server runtime" do servidor de aplicações JBOSS configurado no Eclipse. Como o foco desse artigo não é explicar como configurar servidores de aplicação JBOSS AS no Eclipse, subentendemos que o leitor já utilizar o JBOSS AS no Eclipse. Por último, exportamos o projeto JAVA (do Eclipse ou qualquer outra IDE) como arquivo JAR para a pasta de deploy dos servidores de aplicações utilizado. Geralmente é usado a pasta $JBOSS_HOME/server/$CONFIGURACAO/deploy, onde $JBOSS_HOME é o diretório da instalação do JBOSS e $CONFIGURACAO é a configuração escolhida ("all", "minimal" e outras configurações existentes). Lembrando de mudar a extensão do arquivo JAR gerado para a extensão ".sar", conforme a listagem mostrada no começo do artigo. Automaticamente, o servidor fará o deploy desse novo arquivo SAR e mostrará as seguintes linhas:


12:23:19,273 INFO [STDOUT] StartService [INICIO] - Entrou aki - test.services.AnaliseService - Sat Dec 03 12:23:19 BRST 2011 
12:23:19,275 INFO [STDOUT] StartService [FIM] - Entrou aki - test.services.AnaliseService - Sat Dec 03 12:23:19 BRST 2011 


 O servidor usado foi JBOSS AS 5.1.0, mas os outros servidores funcionarão de maneira semelhante.




CLIENTE

Com o serviço rodando dentro do container JBOSS, agora vamos criar um EJB que acessará esse serviço do arquivo SAR. Como o foco desse artigo não é ilustrar o processo de criar / configurar e disponibilizar EJBs, mostraremos a seguir o código de EJB na versão 3.0 como um cliente que acessará o serviço a cada um tempo definido (periodicamente, pela especificação EJB Timer).

// -----------------------
// Coloque esses métodos num EJB
// e chame o método initialize
// para iniciar o Timer
// e chamar os serviços do arquivo SAR


public void initialize() {
   ctx.getTimerService().createTimer(5000, 5000, null);
   System.out.println("Timers set");
}

@Timeout
public void handleTimeout(Timer timer) {
   System.out.println("@Schedule called at: " + new java.util.Date());

   Object a = null;

   try {
      Context ctx = getInitialContext();

      a = ctx.lookup("AnaliseServiceName");

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

   if (a instanceof AnaliseService) {
      AnaliseService b = (AnaliseService) a;

      b.test("Ola");
   }
}

private InitialContext getInitialContext() throws NamingException {
   final Properties properties = new Properties();

   properties.put(Context.SECURITY_PRINCIPAL, "guest");
   properties.put(Context.SECURITY_CREDENTIALS, "guest");
   properties.put(Context.INITIAL_CONTEXT_FACTORY,
"org.jboss.security.jndi.JndiLoginInitialContextFactory");
   properties.put(Context.PROVIDER_URL, "jnp://localhost:1099");

   return new InitialContext(properties);
}

//-----------------------


Com isso, temos o uso dos serviços definidos no arquivo SAR. Esses serviços podem explorar a API do servidor de aplicações JBOSS para acessar arquivos implantados (deployers) e outras informações sobre o container do JBOSS AS.


Referências


http://www.javabeat.net/tips/117-sar-service-archive-file-in-jboss.html

http://docs.jboss.org/jbossas/admindevel326/html/ch2.chapter.html#d0e3832