Mostrando postagens com marcador JBOSS AS. Mostrar todas as postagens
Mostrando postagens com marcador JBOSS AS. Mostrar todas as postagens

terça-feira, 17 de novembro de 2015

CONFIGURANDO A EXCLUSÃO DO USO DE MÓDULOS PADRÃO NO JBOSS 7



INTRODUÇÃO
 
Nos artigos anteriores (http://www.josepojr.com/2013/10/ordem-de-carregamento-de-classes-jars.html e http://www.josepojr.com/2013/01/isolamento-de-classloaders-no-jboss-as-7.html) foi mostrada a configuração do jboss 7 no arquivo jboss-deployment-structure.xml e algumas regras de preferência no carregamento de dependências. Nesse artigo, vamos mostrar como evitar que um módulo padrão que já vem instalado dentro do JBoss 7 (pasta $JBOSS_HOME/modules) seja carregado. E consequentemente, podemos usar os nossos arquivos .jar sem problemas de dependências e lançamentos de exceções do tipo NoSuchMethodException (método não existente). Esse tipo de exceção pode ocorrer se em tempo de projeto (usando uma IDE por exemplo), usamos os jars de uma biblioteca como por exemplo Apache Http Client na versão 4.5, mas no JBoss 7, já temos por exemplo, uma versão dessa mesma biblioteca na versão 4.2, por exemplo. E ao invocar métodos que só existam na versão 4.5, mas na versão 4.2, os mesmos não existe, o erro NoSuchMethodException pode aparecer. Isso porque em tempo de compilação foi usada a versão 4.5, mas em tempo de execução (projeto war ou ear implantado dentro do JBoss 7), a versão 4.2 (dentro da pasta $JBOSS_HOME/modules) pode ser carregada primeiro em detrimento a versão 4.5 (que pode ou não estar na pasta EAR/lib).
Por isso, precisamos configurar o arquivo .ear gerado para que não ocorra esses erros de dependências que será mostrado nesse artigo.


DESENVOLVIMENTO

Como por exemplo, vamos usar a biblioteca Apache Http Client que pode ser baixada do site:
Esses componentes permite qualquer programa acessar servidores web no protocolo HTTP ou HTTPS. Para isso, fornece modelos para a construção de clientes HTTP no seu programa Java. Sem esses componentes, teríamos que escrever do “zero” (projeto desde o início, novo) um cliente HTTP dentro do nosso programa Java. Isso é possível usando as classes java.net.Socket, java.io.InputStream, java.io.OutputStream e outras semelhantes dentro do JRE (Java Runtime, ambiente de execução do Java mais a máquina virtual) fornecido em toda instalação Java em qualquer dispositivo.
Mas, teríamos que perder um tempo enorme para fazer todas essas chamadas, sendo que com o uso desses componentes e com poucas linhas de códigos já temos um cliente HTTP para usarmos no nosso código.
Portanto, como esse projeto é tem uma licença bem semelhante a um software Open Source e é usado em diversos projetos, o JBoss 7 já vem com essa biblioteca da Apache já configurada como módulo dentro do servidor JBoss 7.
Ao mesmo tempo em que isso é bom, pois já temos um módulo dessa biblioteca para usarmos em nosso projeto, ao mesmo tempo também é ruim, pois queremos usar uma versão mais recente da biblioteca em nossos projetos, por exemplo.
Para isso, vamos configurar o arquivo jboss-deployment-structure.xml para não usar o Apache Http Client existente como módulo dentro do JBoss:

<?xml version="1.0" encoding="UTF-8"?>

<jboss-deployment-structure xmlns="urn:jboss:deployment-structure:1.1">
<ear-subdeployments-isolated>true</ear-subdeployments-isolated>
<deployment>
<exclusions>
<module name="org.apache.httpcomponents" slot="main" />
</exclusions>
<dependencies>
<module name="javax.api"/>
<module name="org.jboss.resteasy.resteasy-jaxrs"/>
<module name="org.infinispan"/>
<module name="deployment.MeuProjeto.ear.MeuEJB.jar"/>
<module name="deployment.MeuProjeto.ear.MeuWAR.war"/>
</dependencies>
</deployment>
<!-- durante o deploy. -->
<sub-deployment name="MeuEJB.jar">
<exclusions>
<module name="org.apache.httpcomponents" slot="main" />
</exclusions>
<local-last value="true"/>
</sub-deployment>
<sub-deployment name="MeuWAR.war">
<dependencies>
<module name="deployment.MeuProjeto.ear.MeuEJB.jar"/>
</dependencies>
<local-last value="true"/>
</sub-deployment>
</jboss-deployment-structure>


Só colocar os trechos marcados em VERMELHO no arquivo jboss-deployment-structure.xml do seu projeto. Nesse exemplo, estamos dizendo que o projeto EJB chamado “MeuEJB.jar” precisa usar a biblioteca Apache Http Client própria e não do JBoss 7. E também, estamos excluindo o uso no ear como um todo como mostra o trecho em VERMELHO dentro da tag <deployment>.
Na pasta /lib dentro do projeto EAR (ou conhecida como EAR/lib) devem estar os jars do Apache Http Client obtido no site:


CONCLUSÃO

Mostramos que o uso de configurações dentro do arquivo jboss-deployment-structure.xml permite refinar algumas configurações que terão impacto tanto no tempo de implantação (deploy) ou em tempo de execução, quando a aplicação for chamada pela primeira vez.
Com isso, podemos usar as versões mais recentes das bibliotecas de terceiros sem conflitar com as mesmas bibliotecas de outras versões já instaladas dentro do JBoss 7.


REFERÊNCIAS











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