Stress-test com Jmeter e Ejb

Testes de estresse e de desempenho são essenciais para verificar requisitos não-funcionais como escalabilidade,  performance e robustez. O objetivo deste post é apresentar como podemos efetuar testes de carga em nossos EJB’s utilizando uma boa ferramenta de testes  de carga que no nosso caso será o JMeter.

Apache JMeter é um software de fonte aberta,  100% puro Java desktop projetado para efetuar testes de performance, carga e stress. Inicialmente ele foi projetado para testes em aplicações Web, mas desde então tem expandido para outras funções tais como desempenho de recursos estáticos e dinâmicos(imagens, Servlets, scripts Perl, Ejb’s, consultas a base de dados, servidores FTP e muito mais).

Ele pode ser usado para simular carga em um servidor,  rede ou objeto, testar a sua robustez ou  analisar o desempenho global com diferentes cenários. Você pode usá-lo para fazer uma análise gráfica de desempenho ou para testar o seu servidor , script, objeto  sob concorrência.

Abaixo farei de forma prática uma demonstração de como podemos efetuar os testes em um EJB rodando no JBoss, para isso vou partir do princípio de que o leitor já possui um EJB rodando em um servidor JBoss.

Para iniciar os testes você precisará de dois jars que deverão ser adicionados em seu classpath que são: ApacheJMeter_core.jar e ApacheJMeter_java.jar estes arquivos se encontram dentro do diretório $JMETER_HOME/lib/ext

Agora vamos criar um service locator (ServiceLocator.java) para fazer os lookups de nosss EJB’s, escolhi este pattern pela sua simplicidade mas você poderia usar um framework como o spring para fazer este trabalho.


package br.com.clariium.jmeter.stresstest;

import java.util.Collections;

import java.util.HashMap;

import java.util.Hashtable;

import java.util.Map;

import javax.naming.InitialContext;

import javax.naming.NamingException;

/**

*

* @author Walyson Trautenmüller

*

*/

public class ServiceLocator {

private InitialContext initialContext;

private Map<String, Object> cache;

private static ServiceLocator instance;

public static synchronized ServiceLocator getInstance() {

       if (instance == null) {

             instance = new ServiceLocator();

       }

       return instance;

}

/**

* Construtor default para lookup local

*/

private ServiceLocator() {

try {

      Hashtable<String, String> map = new Hashtable<String, String>();

      map.put("java.naming.factory.initial",

      "org.jnp.interfaces.NamingContextFactory");

      map.put("java.naming.factory.url.pkgs",

      "org.jboss.naming:org.jnp.interfaces");

      map.put("java.naming.provider.url", "jnp://10.1.1.134:1099");

      initialContext = new InitialContext(map);

      Map<String, Object> cRef = new HashMap<String, Object>();

      cache = Collections.synchronizedMap(cRef);

  } catch (NamingException e) {

            e.printStackTrace();

   }

}

/**

* Faz lookup de ejb remoto

* @param ejbInterface

* @return

* @throws RuntimeException

*/

public Object getObjetoRemoto(String ejbInterface) throws RuntimeException {

       Object result = cache.get(ejbInterface);

       if (result == null) {

               try {

                  result = initialContext.lookup(ejbInterface + "/remote");

                  cache.put(ejbInterface, result);

         } catch (NamingException e) {

                throw new RuntimeException(e);

           }

      }

            return result;

  }

}

Agora vamos escrever o nosso teste (TestaNossoEJB.java)


package br.com.clariium.jmeter.stresstest;

import org.apache.jmeter.protocol.java.sampler.AbstractJavaSamplerClient;
import org.apache.jmeter.protocol.java.sampler.JavaSamplerContext;
import org.apache.jmeter.samplers.SampleResult;

import br.com.cvc.teste.TesteService;

/**
 *
 * @author Walyson Trautenmüller
 * @since 07/06/2010
 */
public class TestaNossoEJB extends AbstractJavaSamplerClient {

 public SampleResult runTest(JavaSamplerContext context) {
    SampleResult results = new SampleResult();
    String par = context.getParameter("par");

    results.sampleStart();
      TesteService testeService = (TesteService) ServiceLocator.getInstance()
      .getObjetoRemoto("TesteEJB");
         if(testeService!=null){
           results.setSuccessful(true);
           results.setResponseCodeOK();
           results.setResponseMessage("'myResult:" + testeService);
           testeService.executaTarefa(par);

    }else {
      results.setSuccessful(false);
    }

     results.sampleEnd();
    return results;
 }

}

Repare que a class “TestaNossoEJB” estende a classe AbstractJavaSamplerClient, esta classe está localizada dentro do jar ApacheJMeter_java.jar que você adicionou em seu classpath, ela possui um método chamado runTest que recebe como parâmetro um objeto “JavaSamplerContext”  caso precisemos receber/manipular algum parâmetro,  e retorna um “SampleResult”. Após estes passos feche o jar e copie-o para dentro de $JMETER_HOME/lib/ext junto com as dependências tais como:  client do seu EJB e como estamos utlizando o  JBoss adicione também as dependências para lookup como o jbossall-client.jar etc… Agora abra a interface gráfica do JMeter e crie uma trhead group para seu teste no menu edit/ add / thread group

Depois de criar uma thrad group vá em  edit / add / sampler / java request, observe que irá aparecer a nossa classe de teste “TestaNossoEJB” , em seguida é só executar o teste no menu run / start ou se preferir ctrl + r

Abaixo o resultado da chamada do meu ejb no console do JBoss

Para receber um parâmetro é simples, basta adicionar uma propriedade  atráves da interface gráfica, no nosso caso demos a ela o nome de “par” e adicionar no código a sintaxe abaixo:

String par = context.getParameter("par");

Relatório do teste:

Você poderá incluir mais funcionalidades a este teste como adicionar usuários simultâneos, alterar o tempo de inicialização, contador de iteração, exibir relatórios mais detalhado referente os resultados da execução etc…

Publicado em jmeter | Deixe um comentário

Url Rewrite Filter

Baseado no maior e mais popular mod_rewrite para apache, UrlRewriteFilter é um Filtro Java Web para qualquer servidor de aplicativos compatível com J2EE web (como o resina, Orion ou Tomcat), permite que você reescreva URLs antes de chegar ao seu código, é uma ferramenta muito poderosa como o mod_rewrite do Apache.
Reescrita de URL é muito comum com o Apache Web Server, mas não era suportado na maioria dos servlet container java, os principais mecanismos utilizado são:

  • URL Amigável / Abstração de URL: mantém “ordenado” as URLs, independentemente da tecnologia ou framework (JSP, Servlet, Struts, JSF, etc).
  • Detecção de Browser: Permite você reescrever URLs com base em requisições HTTP (como agente de usuário ou charset).
  • Reescrita com base em dados: Permite que você envie ou redirecine para outra URL baseado em data/hora (bom para interrupções planejadas).
  • Conteúdo Movido: Permitir uma mudança elegante no conteúdo ou mesmo no CMS.

UrlRewriteFilter usa apenas um arquivo xml chamado urlrewrite.xml (devendo está localizado abaixo do diretório WEB-INF)

A maioria dos parâmetros podem ser Perl5, expressões regulares ou expressões curinga. Esta combinação o torna muito poderoso.

Configurando UrlRewriteFilter

Abaixo irei fazer uma pequena demonstração de como se configura na sua aplicação web, estarei utilizando como sempre o velho e bom maven2, para aqueles que não utilizam o maven segue o link para download.

Dependência a ser adionado no seu pom.xml (para quem estiver usando o maven)


...

<dependency>
<groupId>org.tuckey</groupId>
<artifactId>urlrewritefilter</artifactId>
<version>3.0.4</version>
</dependency>

...

No seu web.xml adicione os seguintes filtros:


<filter>
<filter-name>UrlRewriteFilter</filter-name>
<filter-class>org.tuckey.web.filters.urlrewrite.UrlRewriteFilter</filter-class>

<init-param>
<param-name>confReloadCheckInterval</param-name>
<param-value>60</param-value>
</init-param>

<init-param>
<param-name>confPath</param-name>
<param-value>/WEB-INF/urlrewrite.xml</param-value>
</init-param>
</filter>

<filter-mapping>
<filter-name>UrlRewriteFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>

Crie um xml chamado urlrewrite.xml e coloque abaixo do diretório WEB-INF


<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE urlrewrite PUBLIC "-//tuckey.org//DTD UrlRewrite 2.6//EN"
"http://tuckey.org/res/dtds/urlrewrite2.6.dtd">

<urlrewrite>
<rule>
<from >/from/de.jsp</from>
<to type="forward">/to/para.jsp</to>
</rule>
</urlrewrite>

Crie um diretório abaixo de webapp chamado de “from” e adicione uma jsp com o nome “de.jsp”:


<html>
<head>
<title>De</title>
</head>
<body>
<table>
<tr>
<td>De</td>
</tr>
</table>
</body>
</html>

Crie um diretório abaixo de webapp chamado “to” e adicione uma jsp com o nome “para.jsp”:


<html>
<head>
<title>Para</title>
</head>
<body>
<table>
<tr>
<td>Para</td>
</tr>
</table>
</body>
</html>

Pronto, feche o war e faça o deploy no seu servlet container, no meu caso estou usando o jboss por causa do tomcat que já vem embutido em sua distribuição mas ele pode ser usado no tomcat, jetty, glassfish ou weblogic. Em seguida faça a chamada a: http://localhost:8080/urlrewrite/from/de.jsp, perceba que ela foi redirecionada automaticamente para outra página porém a url continuou a mesma.

Você pode também acionar uma servlet, para isto vamos criar uma classe extendendo de HttpServlet

public class TesteUrlRewrite extends HttpServlet{

/* (non-Javadoc)
 * @see javax.servlet.http.HttpServlet#doGet(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse)
 */
 @Override
 public void doGet(HttpServletRequest req, HttpServletResponse resp)
 throws ServletException, IOException {
 executa();
 }

 public void executa(){
 System.out.println("fui acionado");
 }

}

Agora vamos mapear nossa servlet no web.xml

<servlet>
 <servlet-name>testeUrlRewrite</servlet-name>
 <servlet-class>br.com.urlrewrite.TesteUrlRewrite</servlet-class>
 </servlet>
 <servlet-mapping>
 <servlet-name>testeUrlRewrite</servlet-name>
 <url-pattern>/testeUrlRewrite</url-pattern>
 </servlet-mapping>

Em seguida vamos adicionar esta servlet no nosso urlrewrite.xml conforme abaixo:

....
<run class="br.com.urlrewrite.TesteUrlRewrite" method="doGet" />

......

que ficará assim:

<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE urlrewrite PUBLIC "-//tuckey.org//DTD UrlRewrite 2.6//EN"
 "http://tuckey.org/res/dtds/urlrewrite2.6.dtd">

<urlrewrite>

 <rule>
 <from >/de/de.jsp</from>
 <run class="br.com.urlrewrite.TesteUrlRewrite" method="doGet" />
 <to type="forward">/para/para.jsp</to>
 </rule>
</urlrewrite>

Ele deverá exibir no console a seguinte mensagem:

14:32:01,538 INFO  [STDOUT] fui acionado

Outros exemplos aqui
Este post é bem simples mas você poderá usufruir de praticamente todos os recursos que já vinham sendo utilizados no apache com mod_rewrite.

Fonte: http://tuckey.org/urlrewrite/

Publicado em web | 1 Comentário

Segurança customizada com realm no Glassfish

Segurança é um ítem fundamental para quem desenvolve aplicações corporativas, em um dos projetos por onde passei me foi designado a tarefa de implementar um mecanismo de segurança personalizado, o servidor de aplicação utilizado era o Glassfish no qual eu gostaria de escrever aqui parte da implementação mas não seria justo sem antes mostrar minha fonte pois tudo que eu fiz ou basicamente tudo eu tirei de um livro do Masoud Kalali, o livro é bom e eu recomendo pois ele aborda exclusivamente o Glassfish no qual suporta 5 tipos de segurança que são:

File Realm: Ao utilizar este realm todos os nomes de usuários, senhas e grupos são armazenadas em um arquivo de texto simples.
JDBC Realm: Este realm é configurado via JDBC onde as informações de usuários, senhas e grupos estão armazenadas em um banco de dados.
LDAP Realm: Para autenticação em um LDAP seja ele um Active Directory, Red Hat Directory Server, OpenDS ou Sun Java System Directory Server Enterprise Edition,
(no meu caso acabei fazendo a minha implementação utilizando este tipo de atutenticação e autorização)
Solaris Realm: Este realm é usado para autenticar usuários em uma arvore de diretórios do Solaris.
Certificate Realm: Este nos permite realizar a autenticação SSL mútuo, com base nos certificados de cliente.

Abaixo segue a capa do livro:

Gosto muito do Glassfish e não é por causa da sua interface de administração rica e objetiva aliás, sempre edito o domain.xml na mão, mas o maior motivo desta “admiração” é o fato de não ter problemas como teriamos no jboss quanto ao seu maldito classloaders.

Estou preparando um exemplo simples de como eu fiz esta implementação e em breve postarei aqui no blog.

Publicado em Glassfish | Deixe um comentário

Resolvendo problemas com Spring + JSF + Jboss 6

Ao migrar minha aplicação do WebLogic 10 para o jboss 6 me deparei com um problema, o Spring não conseguia injetar os managed beans do jsf devido a uma incompatibilidade entre jboss e spring, neste caso para resolver este problema é necessário que seja incluído no pom.xml (para os casos em que estiverem usando o maven2) ou adicionar no seu classpath as dependências do Snowdrop.
O Snowdrop é uma biblioteca que contém extensões JBoss específicas para trabalharem com o Spring Framework, elas podem ser usadas sempre que as implementações fornecidas pelo Spring não funcionarem corretamente quando em conjunto com o Jboss.
É importante ressaltar que existe a versão 1.0.0.GA porém ela ainda contém alguns bugs que foram solucionados na versão 2.0.0.M1, eu acabei
criando um pom.xml (conforme abaixo) para a versão 2.0.0.M1 porém ela poder ser baixado através do site do projeto.

<dependency>
    <groupId>org.jboss.snowdrop</groupId>
    <artifactId>snowdrop-deployers</artifactId>
    <version>2.0.0.M1</version>
 </dependency>
 <dependency>
    <groupId>org.jboss.snowdrop</groupId>
    <artifactId>snowdrop-vfs</artifactId>
    <version>2.0.0.M1</version>
</dependency>

O nome dos jar’s:


snowdrop-vfs-<version>.jar
snowdrop-deployers-<version>.jar

Em seguia você deverá mapear no web.xml da sua aplicação a classe: VFSXmlWebApplicationContext, está classe encontra-se dentro do jar: snowdrop-vfs-<version>.jar no qual você adicionou no classpath da sua aplicação.

web.xml

<initparam>
     <paramname>contextClass</paramname>
     <paramvalue>org.jboss.spring.vfs.context.VFSXmlWebApplicationContext</paramvalue>
</initparam>

É importante observar que as lib’s (tanto do snowdrop quanto do spring) devem estar no mesmo classpath, ou seja, elas devem estar dentro de $JBOSS_HOME/server/default/lib ou dentro de $SUA_APP_HOME/WEB-INF/lib.

Espero ter ajudado e até a próxima.

Publicado em Spring | 4 Comentários