12/04/2011

Debug do Classloader no Weblogic

É comum ao tentarmos fazer o deploy de uma aplicação recebermos um erro de ClassNotFoundException. Este é o tipo de erro bem chato de descobrir e algumas vezes temos certeza que a classe está presente no lib do domínio ou disponível para aplicação de alguma forma, seja como shared lib ou no classpath do servidor direto. E então o que fazer, como pode estar acontecendo de a classe COM CERTEZA estar disponível e mesmo assim a exceção de ClassNotFound estar ocorrendo? Bem, nesse caso é bastante útil fazer o classloader ficar em modo verbose para vermos direitinho quais as classes e em que ordem o weblogic está carregando-as.

Para fazer isso basta adicionarmos como parâmetro de JVM do servidor desejado o seguinte:

-Dweblogic.utils.classloaders.FilteringClassLoader.Verbose


Feito isso ao reiniciarmos o servidor iremos ver o classloader aparecendo para cada classe que for procurada, neste formato:

...
[FilteringClassLoader] : **** FilteringClassLoader ... findClass(..) weblogic.jndi.WLInitialContextFactory
[FilteringClassLoader] : **** FilteringClassLoader ... findClass(..) weblogic.jndi.factories.java.javaURLContextFactory
[FilteringClassLoader] : **** FilteringClassLoader ... findClass(..) String
[FilteringClassLoader] : **** FilteringClassLoader ... findClass(..) com.bea.common.security.store.data.String
[FilteringClassLoader] : **** FilteringClassLoader ... findClass(..) String
[FilteringClassLoader] : **** FilteringClassLoader ... findClass(..) com.bea.common.security.store.data.String
[FilteringClassLoader] : **** FilteringClassLoader ... findClass(..) String
[FilteringClassLoader] : **** FilteringClassLoader ... findClass(..) com.bea.common.security.store.data.String
[FilteringClassLoader] : **** FilteringClassLoader ... findClass(..) String
...


Com o debug do classloader fica bem mais fácil entender e descobrir a causa do ClassNotFoundException e com isso solucionar o problema.
Fica também uma dica, caso seja necessário pode-se inverter o classloader da aplicação web para que o weblogic utilize como preferenciais os .jar empacotados no lib do seu .war, para isso basta colocar a seguinte configuração no weblogic.xml da sua aplicação:

...
    
        true
    
...


[]s

07/04/2011

Migração do Projeto Seam para rodar no Weblogic 10.X - Parte 2

Este post dá continuidade a uma série de posts que estou escrevendo sobre a migração de um projeto que utilize JBoss Seam para rodar em weblogic, estou usando neste caso o Weblogic 10.3.3

O que me motivou a fazer este post é que a documentação oficial do JBoss Seam tem um capítulo sobre o Weblogic mas em todas as vezes que tentei seguí-la não obtive sucesso. Então segue o que fiz com as devidas alterações para que funcionasse.

A primeira parte deste post que cobre a criação do projeto com JBoss Seam pode ser encontrada neste link:

http://mmaiacupofcoffee.blogspot.com/2010/05/jboss-seam-criacao-de-projeto.html

Seguindo os passos do projeto criado no link acima temos então um projeto do Seam padrão, o próximo passo é importá-lo no eclipse para alterarmos o que for necessário. Eu utilizei uma versão do Eclipse Helios com JBoss Tools, se precisar de uma referência veja este post.

1) Criação do arquivo weblogic.xml - para este primeiro passo basta criar um arquivo chamado weblogic.xml no mesmo diretório onde está o web.xml


    10.3.3
    seam_weblogic



2) Mudar os arquivos persistence-prod.xml e persistence-dev.xml para funcionar com o weblogic, segue o meu persistence-dev.xml, para o prod fazer as alterações normais necessárias relativas ao banco de dados, criação de tabelas, etc..


             
   
      org.hibernate.ejb.HibernatePersistence
      seam_weblogic_ds
      
         
         
         
         
         
         
         
         
      
   
    



3) No web.xml registrar o seguinte listener:

  com.sun.faces.config.ConfigureListener



4) Mudar no build.xml o default target para archive e complementar as libs a serem copiadas pro pacote conforme fragmento abaixo:


...

    
        
        
        
        
        
         
        
        
        
        
        
        
        
        
             
        
        
        
             
        
        
        
        
        
        
        
    
 



Feito isso basta navegar em um console para a raiz do projeto e executar o ant default mesmo:
ant

Isso irá criar o war compatível com weblogic no diretório dist do seu projeto. Este .war é compatível com weblogic e vc pode fazer o deploy pelo console normalmente ou se o seu weblogic estiver no modo de desenvolvimento simplesmente copiar este arquivo para o diretório autodeploy do seu domínio.

Em alguns casos percebi a necessidade de inverter o classloader do weblogic, se no passo acima vc ainda não conseguir rodar vc pode tentar inverter o classloader do weblogic.

Este é o procedimento que funcionou no meu caso com .war gerado no seam. Não tentei e não recomendo utilização do Seam com EJBs no weblogic até este momento, por questões de estabilidade e aderência às especificações. Recomendo somente utilização do seam com pojos de camada web se for utilizá-lo com weblogic, mas se este for o seu caso vc encontra informações de como fazer isso na doc. oficial do Seam.

[]s

06/09/2010

Weblogic - Persistência de sessão em Banco de Dados

Apesar de raramente ser necessário ou mesmo recomendado, já passei por situações onde a persistência de sessão(HttpSession) do usuário tivesse como requisito de arquitetura a necessidade de ser persistida em base de dados quando normalmente o recomendado é fazer em memória por motivos de performance. Quando for necessário fazer isso com utilização de weblogic é bem simples.

Primeiro precisamos da base de dados, neste exemplo vou usar o postgresql, que é free e fácil de usar e instalar. Fiz, a algum tempo, um quickstart em um outro post que sempre me é útil.
Bem, uma vez instalado o postgres basta criar uma base de dados, que nesse exmplo tem as configurações:

-Nome da Base: wl_session
-Usuário: weblogic
-Senha: weblogic


Feito isso deve-se criar a base de dados para persistência de sessão conforme script disponibilizado, perceba que existem scripts específicos para diversos banco de dados como Oracle, DB2, etc.

Bem, neste caso utilizo o script que adaptei para o Postgres:
create table wl_servlet_sessions
  ( wl_id VARCHAR(100) NOT NULL,
    wl_context_path VARCHAR(100) NOT NULL,
    wl_is_new CHAR(1),
    wl_create_time BIGINT,
    wl_is_valid CHAR(1),
    wl_session_values bytea,
    wl_access_time BIGINT,
    wl_max_inactive_interval INTEGER,
   PRIMARY KEY (wl_id, wl_context_path) );


Após a criação da tabela na base baixar o driver e criar um pool de conexões no weblogic apontando para esta base. Neste exemplo utilizei os atributos de pool:
- Nome do Pool: PostgresDS
- jndi name do pool: jdbc/Postgres

Com o pool feito, é só configurar no weblogic.xml da sua aplicação web para utilizar o pool configurado, conforme no exemplo abaixo:


    10.3.2
    sessaodb
    
        JDBC
        PostgresDS
        jdbc/Postgres
    


Pronto, agora ao acessar uma página da aplicação uma nova sessão será criada na base de dados e o weblogic irá persistir as sessões de usuário nesta tabela, enquanto as mesmas estiverem ativas, conforme a imagem abaixo ilustra.


Lembre-se que esta não é uma opção que melhor se adeque se sua aplicação precisar de foco em performance e escalabilidade e normalmente deve ser utilizada somente se for uma necessidade específica do projeto. []s

12/07/2010

Weblogic, um Message Driven Bean Simples

Escrevi em outras oportunidades sobre criação de filas ou tópicos JMS no Weblogic e de como este recurso é importante em um ambiente distribuído e corporativo. Para ilustrar vou postar aqui um exemplo simples de um MDB que consome de um tópico JMS simples. Não vou comentar sobre os elementos do MDB detalhadamente, vou focar na implementação. Para ilustrar vou utilizar para o exemplo uma página JSF que posta uma mensagem em um tópico e um MDB com annotations para consumir a mensagem.

Primeiro, para o exemplo funcionar deve-se criar no weblogic um topico simples com as seguintes configurações:

Nome: Exemplo MDB
Nome JNDI: jms.distributed.Topic

Se quiser ver detalhadamente como criar este tópico, fiz um tópico sobre esse assunto no link: http://mmaiacupofcoffee.blogspot.com/2010/02/weblogic-jms-parte-iii-criacao-de-fila.html. Bastando adaptar e criar um tópico(Topic) ao invés de uma fila(Queue).



Os trechos de código relevantes para o exemplo explico à seguir. A parte JSF do exemplo deve ser "empacotada" em um .war e o ejb em um .jar, conforme definido pela especificação.

O cliente de exemplo que publica no tópico é escrito com JSF, composto por uma página e uma Action.
Abaixo posto detalhes relevantes da página que publica a mensagem e define-se quantas vezes será postada. O ActionBean é registrado com o nome mensagemBean no deployment descriptor. O exemplo usa notação JSF simples e por isso não vou detalhar aqui:


    Texto da Mensagem:
Quantidade:


A segunda parte do cliente que publica a mensagem é o ActionBean que recebe os parâmetros dos campos da página e efetivamente posta a mensagem no tópico utilizando JMS. Perceba que um loop é criado para postar várias mensagens se desejado. Para o exemplo ficar mais claro não estou utilizando anottations para fazer injection de dependência de contexto.
package exemplo.action;

import java.util.logging.Logger;

import javax.jms.JMSException;
import javax.jms.Session;
import javax.jms.TextMessage;
import javax.jms.Topic;
import javax.jms.TopicConnection;
import javax.jms.TopicConnectionFactory;
import javax.jms.TopicPublisher;
import javax.jms.TopicSession;
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NamingException;

public class PublicaTopicoAction {
 
 private Logger log = Logger.getLogger(PublicaTopicoAction.class.getName());

 private String mensagem;
 private int quantidadeMensagens;
 
 protected Context ctx;
 protected TopicPublisher tpublisher;
 protected Topic topic;
 protected TextMessage msg;
 protected TopicConnection tcon;
 protected TopicSession tsession;
 
 public final static String JMS_FACTORY = "weblogic.jms.ConnectionFactory";
 
 public final static String TOPIC = "jms.distributed.Topic";

 protected TopicConnectionFactory tconFactory;
 
 public PublicaTopicoAction()
 {
  log.info("Construtor PublicaTopicoAction");
  try {
   ctx = new InitialContext();
   tconFactory = (TopicConnectionFactory) ctx.lookup(JMS_FACTORY);
   tcon = tconFactory.createTopicConnection();
   tsession = tcon.createTopicSession(false, Session.AUTO_ACKNOWLEDGE);
   topic = (Topic) ctx.lookup(TOPIC);
   tpublisher = tsession.createPublisher(topic);
   tcon.start();
  } catch (NamingException e) {
   log.severe("Erro ao recuperar o contexto para fazer lookup");
   e.printStackTrace();
  } catch (JMSException e) {
   log.severe("Ocorreu um erro ao conectar no topico: " + e.getMessage());
   e.printStackTrace();
  }
 }
 
 public String enviaMensagem()
 {
  log.info("Entrou PublicaTopicoAction.publicaMensagem");
  for (int i = 0; i < quantidadeMensagens; i++) {
   publicaMensagemTopic(mensagem + "_" + i); 
  }
  log.info("Executou PublicaTopicoAction.publicaMensagem");
  return "OK";
 }
 
 private void publicaMensagemTopic(String mensagem) {
  try {
   log.info("Entrou PublicaTopicoAction.publicaMensagemTopic");
   msg = tsession.createTextMessage();
   msg.setText(mensagem);
      tpublisher.publish(msg);
   log.info("Executou PublicaTopicoAction.publicaMensagemTopic");
  } catch (Exception e) {
   log.severe("Ocorreu um erro ao postar mensagem na fila");
   e.printStackTrace();
  }
 }
 
 public String getMensagem() {
  return mensagem;
 }

 public void setMensagem(String mensagem) {
  this.mensagem = mensagem;
 }

 public int getQuantidadeMensagens() {
  return quantidadeMensagens;
 }

 public void setQuantidadeMensagens(int quantidadeMensagens) {
  this.quantidadeMensagens = quantidadeMensagens;
 }
 
}


Finalmente o código do Message Driven Bean que é bem simples e assim que uma mensagem chega no tópico ele consome a mesma executando o método onMessage, conforme definido pela especificação. Perceba que o link com o Tópico é feito através de anottations no MDB e que para exemplos simples como este não é necessário a criação de arquivos xml de configuração, o deployment descriptor para EJBs é opcional na versão de EJB 3.0 ou posteriores.

package exemplo.mdb;

import java.util.logging.Logger;

import javax.ejb.ActivationConfigProperty;
import javax.ejb.MessageDriven;
import javax.jms.JMSException;
import javax.jms.Message;
import javax.jms.MessageListener;
import javax.jms.TextMessage;

@MessageDriven(activationConfig = { @ActivationConfigProperty(propertyName = "destinationType", propertyValue = "javax.jms.Topic") }, mappedName = "jms.distributed.Topic")
public class TopicConsumerMDB implements MessageListener {

 Logger log = Logger.getLogger(TopicConsumerMDB.class.getName());

 public TopicConsumerMDB() {
  log.info("Construtor TopicConsumerMDB");
 }

 /**
  * @see MessageListener#onMessage(Message)
  */
 public void onMessage(Message message) {
  log.info("Entrou onMessage");
  try {
   TextMessage textMessage = (TextMessage) message;
   String messageID = textMessage.getJMSMessageID();
   log.info("ID da mensagem recuperada ==>> " + messageID);
   String mensagem = textMessage.getText();
   log.info("Mensagem recebida ==>> " + mensagem);
  } catch (JMSException e) {
   log.severe("Ocorreu um erro ao recuperar informacoes da mensagem ==>> "
       + e.getMessage());
   e.printStackTrace();
  }
  log.info("Executou onMessage");
 }
}


[]s

30/06/2010

Weblogic, configuração de domínios.

Este é um post simples, o intuito é mostrar como fazer um backup de um domínio já configurado e poder restaurá-lo posteriormente. Isto é muito útil em diversas situações do dia a dia em uma empresa que utilize o weblogic server.

Para este exemplo vou utilizar um domínio já criado com um servidor chamado Server-1 com uma configuração de fila JMS atribuída a este servidor.

Para fazer um template deste domíno basta utilizar a ferramenta "Domain Template Builder" do weblogic.

Para executar o domain template builder execute o script: ${WL_HOME}/commmom/bin/config_builder.sh, é importante lembrar que esta versão precisa de ambiente gráfico para executar. Se não tiver suporte a ambiente gráfico no servidor que deseja criar o template pode-se utilizar os comandos pack e unpack conforme descrito em detalhes na documentação oficial do weblogic.

Para fazer o template do domínio, que será um .jar, executar o config_builder.sh para unix e derivados ou config_builder.cmd no caso de windows.

Depois é só selecionar a opção "Create a Domain Template" e depois seguir o passo a passo que é auto-explicativo. No final será criado um arquivo com a extensão .jar que poderá ser utilizado na criação de novos domínios como explico à seguir.

Criei um template chamado dominio_exemplo_weblogic-v10.3.2.0.jar, agora para recriar este domínio em qualquer outro servidor basta levar este .jar para o novo servidor com os binários de weblogic já instalados e executar o wizard de configuração de domínios do weblogic em ${WL_HOME}/commom/config.sh

No wizard selecionar "Create a New Weblogic Domain" e no segundo passo selecionar a opção "Base this domain on an existing template" e apontar para o .jar gerado com a ferramenta "configuration builder", ver imagem abaixo.



Depois é só seguir o restante do passo a passo que é auto-explicativo e o domínio será criado com as configurações recuperadas do template.

Iniciar os servidores do domínio criado e verificar que estes terão as configurações idênticas ao domínio original. []s