Mostrando postagens com marcador Java. Mostrar todas as postagens

ATG: RqlStatement com Cache interno


Resolvi por curiosidade estudar o método estático RqlStatement.parseRqlStatement. No Javadoc da classe, pude observar que existem duas formas de utilizar o método com passagem de String para representar o RQL, algo muito comum quando estamos no mundo ATG e seus infindáveis properties de configuração. As duas formas podem ser vistas abaixo:

RqlStatement.parseRqlStatement(rql);

e

RqlStatement.parseRqlStatement(rql, cacheRqlStatement);

Quero focar meus esforços em apresentar a diferença entre esses dois métodos. Quando utilizado RqlStatement.parseRqlStatement(rql), o que realmente acontece é a execução do parse sem manter o objeto convertido em cache. Para deixar claro, esse cache é interno a classe.

Já no segundo método, o Javadoc descreve o processo da seguinte maneira:

"Parses an RqlStatement from the given String. If pCacheRqlStatement is true, then the RqlStatement that is created from this operation will be saved in an internal cache with the String pStatement as the key. The next time this same string is passed to parseRqlStatement, the cached RqlStatement will be returned, so we don't have to re-parse the same string over and over again. Only use this method for statements that you'll definitely be re-using over again, and if the code you're using does NOT cache the statement already".

Isso quer dizer que ao utilizar o segundo método ganha-se a possibilidade de armazenar no cache interno do RqlStatement uma referência do objeto convertido, não sendo necessário efetuar novamente a conversão do mesmo pela própria classe.

Para se ter uma ideia do impacto disso, montei 2 testes com JUnit: 1 sem cache e 1 com cache (informando o segundo parâmetro como true). Na imagem abaixo, pode-se ver como é alarmante a diferença entre ambos os processos quando temos 1 milhão de iterações. Sem cache o processo leva 62 segundos, mas com cache leva apenas 0,843 segundos.



Sendo assim, o melhor caminho seria utilizar RqlStatement.parseRqlStatement(rql, true), favorecendo a performance dos processos, otimizando o tempo em novas chamadas ao parse que possuam o mesmo parâmetro de RQL, não sendo necessário armazenar referências convertidas em atributos de classe, pois a classe RqlStatement faz isso.

Talvez você se sinta inclinado a querer a possibilidade de limpar esse cache quando quizer. Esse geralmente é um controle que Desenvolvedores do mundo ATG gostam de ter. Entretanto, lhe afirmo que esse não é um cache perigoso, daqueles que você realmente precisa limpar, pois algo foi atualizado em banco e agora a aplicação precisa refletir. Não! Esse é um cache interno a classe RqlStatement. Se o RQL for alterado por um properties dinâmico, tudo que a classe irá fazer na próxima iteração é armazenar o novo RQL convertido, sendo que o anterior não será mais utilizado.

Gostou? Compartilhe esse post =)

Dummy SMTP: JavaMail API + DevNullSMTP

O que quero mostrar é uma forma de testar o envio de e-mails em ambiente de desenvolvimento simulando um falso servidor SMTP com o framework DevNull SMTP. Pretendo mostrar duas formas de fazer isso: uma utiliza JndiHelper (para usuário de WebLogic Server) e outra utiliza Session (classe integrante da API JavaMail).

Com JndiHelper


1. Crie uma pasta no sistema (exemplo: \devNullSMTP)

2. Baixar o jar do framework DevNull SMTP e coloque nessa pasta.
Link: http://www.aboutmyip.com/AboutMyXApp/DevNullSmtp.jar

3. No console do WebLogin Server vá em Mail Session e crie um novo com os seguintes atributos:

Name: SMTPMailSession
JNDI Name: SMTPMailSession
JavaMail Properties:
mail.debug=True
mail.smtp.port=25
mail.transport.protocol=smtp
mail.smtp.host=127.0.0.1

4. Crie dentro da pasta \devNullSMTP a pasta para receber os emails (exemplo: \emails)

5. Executar em linha de comando o seguinte:

java -jar DevNullSmtp.jar -s emails

Para mais comandos ver http://www.aboutmyip.com/AboutMyXApp/DevNullSmtpUsage.jsp

6. No console que irá abrir, clique em Start Server.

7. Pronto. Observações: Todo e-mail enviado vai para pasta \emails com a terminação EML e pode ser visualizada no Notepad++. O console do DevNull SMTP loga todo o processo em 4 abas disponíveis, incluindo o próprio EML. O console do Eclipse efetua logs também, mas nada além do console do DevNull SMTP.

Com Session


O mesmo processo para usuário de JndiHelper com excessão do passo 3, pois as propriedades são setadas em código da seguinte maneira:

Properties props = new Properties();
props.put("mail.debug", "true");
props.put("mail.smtp.port", "25");
props.put("mail.transport.protocol", "smtp");
props.put("mail.smtp.host", "127.0.0.1");
Session session = Session.getInstance(props, null);

O restante do processo segue da mesma forma.

Conclusão


Esse conhecimento permitiu a independência de desenvolvimento de funcionalidades que utilizam envio de e-mail. Tive muitos problemas no passado com funcionalidades desse tipo e sempre dependia de ambiente configurado para os testes, quando encontrava um erro não era apenas uma correção, mas também tinha que esperar por um deploy em ambiente de homologação. Espero que isso também seja útil para você.

Fonte




Use isEmpty em vez de equals


 "A perfeição é feita de pequenos detalhes - não é apenas um detalhe." (Michelangelo)

Gostaria de começar esse post ressaltando a famosa frase de Michelangelo ditada acima que fala sobre "detalhes". Em minha busca por conhecimento dedico meu tempo justamente a isso, detalhes. Não basta para mim ter a solução em mãos, é preciso mais, é preciso saber como chegar até esta solução, cada detalhe da implementação de um algoritmo é o que o faz ter usabilidade, flexibilidade e clareza, porém nesse post quero tratar de algo mais interessante, um detalhe que envolve desempenho.

Assim como qualquer linguagem, Java tem seus detalhes de implementação que gosto de explorar. Nesse post quero mostrar o porque deve ser usado isEmpty() em vez de equals(""). Primeiramente vamos a documentação de ambos os métodos:

isEmpty - "Returns true if, and only if, length() is 0".
equals - "Compares this string to the specified object. The result is true if and only if the argument is not null and is a String object that represents the same sequence of characters as this object".

Pela documentação de cada método já temos uma simples noção de implementação onde que isEmpty utiliza um atributo privado para verificar se é igual a zero, apenas isso enquanto equals utiliza verificação de argumento nulo e sequencia de caracteres, o que com certeza é uma implementação mais penosa para um caso tão simples como a verificação de uma string vazia. Equals abrange verificação para casos mais complexos. Vamos ao código de cada método:

isEmpty
public boolean isEmpty() {
    return count == 0;
}
equals
public boolean equals(Object anObject) {
    if (this == anObject) {
        return true;
    }
    if (anObject instanceof String) {
        String anotherString = (String) anObject;
        int n = count;
        if (n == anotherString.count) {
            char v1[] = value;
            char v2[] = anotherString.value;
            int i = offset;
            int j = anotherString.offset;
            while (n-- != 0) {
                if (v1[i++] != v2[j++])
                    return false;
            }
            return true;
        }
    }
    return false;
}

Como esperado, o método equals é dedicado a comparação de strings diversas, enquanto o método isEmpty ataca um problema específico onde posso apenas querer saber se essa string esta vazia ou não.

Desempenho


Para o teste de desempenho fiz dois testes com jUnit, cada um atacando um dos métodos. Cada teste possui um loop de 100 milhões de iterações mostrando uma diferença de tempo considerável. Acredito que grandes empresas com sites que superam acessos de 1 milhão de pessoas rodando diversas classes contendo diversas vezes uma comparação utilizando equals("") resulte em algo semelhante, senão pior.

public class StringEmptyTest {
    
    @Test
    public void isEmpty() {
        String test = "";
        for (int i = 0; i < 100000000; i++) {
            test.isEmpty();
        }
    }
    
    @Test
    public void equals() {
        String test = "";
        for (int i = 0; i < 100000000; i++) {
            test.equals("");
        }
    }

}


No resultado, isEmpty() foi 5,6 vezes menor em seu tempo de execução.

Conclusão


Quando Michelangelo cunhou sua frase, assim como tantas outras, o contexto era outro obviamente, mas programar não deixa de ser uma arte e assim como no contexto de Michelangelo, nós no nosso contexto precisamos entender o quanto um detalhe é importante. Com certeza utilizar isEmpty ou equals em um programa com poucos acessos não fará diferença, o que pretendo dizer com esse post é justamente o que a frase de Michelangelo diz "A perfeição é feita de pequenos detalhes...", junte esse detalhe, mais aquele outro e mais um e terá uma melhoria de desempenho. 

HashCode.java: uma alternativa

Em uma das minhas últimas aquisições obtive o livro Java Efetivo de Joshua Bloch, uma referência para quem conhece Java e quer melhorar seu entendimento sobre detalhes da linguagem. O item 9 do 3º capítulo é um tanto interessante, explicando regras de sobreposição do método hashCode. Não vou transcrever aqui o que fala o livro, mas quero deixar uma alternativa que acho interessante para geração de hashCodes quando ocorre a sobreposição do método levando em consideração o que fala no livro. Conceitos como flexibilidade e manutenibilidade e até o princípio da Responsabilidade Única foram levados em consideração, já no quesito desempenho será apresentado uma alternativa.

O livro fala sobre como se deve implementar a conversão de atributos de uma classe em hashCode, o cálculo e o tratamento, mas sempre aprendi que a lógica de uma parte quando pode viver isolada deve ser isolada, isso aumenta a flexibilidade do sistema e consequentemente a manutenibilidade, com isso, a alternativa que apresento é uma classe HashCode contendo toda a lógica para anexar os atributos e obter um hashCode. Segue a classe:

public final class HashCode {
    
    private HashCode() {}
    
    public static HashCode create() {
        return new HashCode();
    }
    private int _result = 17;
    
    public HashCode append(int value) {
        _result = 31 * _result + value;
        return this;
    }
    public HashCode append(boolean value) {
        return append(value?1:0);
    }
    public HashCode append(byte value) {
        return append((int)value);
    }
    public HashCode append(char value) {
        return append((int)value);
    }
    public HashCode append(short value) {
        return append((int)value);
    }
    public HashCode append(long value) {
        return append((int)(value^(value>>>32)));
    }
    public HashCode append(float value) {
        return append(Float.floatToIntBits(value));
    }
    public HashCode append(double value) {
        return append(Double.doubleToLongBits(value));
    }
    public HashCode append(Object value) {
        return append(value==null?0:value.hashCode());
    }
    @Override
    public int hashCode() {
        return _result;
    }
}

Perceba que utilizei alguns outros conceitos como um construtor estático, sobrecarga e fluent interfaces. A classe é final, pois acredito que ela não deva ser estendida e o próprio método hashCode de Object é sobrescrito aqui para retornar o resultado final.

Usabilidade


No caso de atributos onde não exista uma coleção o código ficaria como mostrado no exemplo abaixo.

@Override 
public int hashCode() {
    return HashCode.create()
            .append(_name) // String
            .append(_url) // URL
            .append(_descriptiveStatus) // String
            .append(_timer) // long
            .append(_effect) // boolean
            .hashCode();
}

Já no caso de uma coleção, preferi não implementar nada, pois o que deve ser levado em conta numa coleção somente cada programador saberá, lembrando que no caso de arrays a classe Arrays possui vários métodos para geração de hashCodes, vale a pena conferir. Quando existir uma coleção, prefiro iterar sobre ela e obter os atributos que considero melhor. Abaixo um exemplo:

@Override
public int hashCode() {
    HashCode result = HashCode.create();
    result.append(_nameBedroom); // String
    Enumeration<String> keys = _bedroom.keys();
    while (keys.hasMoreElements()) {
        String key = (String) keys.nextElement();
        result.append(_bedroom.get(key).hashCode()); // int
    }
    return result.hashCode();
}

Desempenho


Para testar o desempenho do código com e sem a classe HashCode fiz dois testes com jUnit, ambos efetuam o mesmo calculo, cada um sobre um for de 100 milhões de loops que proporciona uma visão mais humana, um dos testes não utiliza a classe HashCode, o outro sim.


Percebe-se a diferença de tempo, quase o dobro do tempo para executar o mesmo cálculo quando se utiliza  a classe HashCode. This is bad!!!

public class HashCodeTest {
    
    String nome = "Vinicius Knob";
    int anoNascimento = 1989;
    long dataHoje = Calendar.getInstance().getTimeInMillis();
    boolean java = true;

    @Test
    public void testSemClasse() {
        for (int i = 0; i <= 100000000; i++) {
            int result = 17;
            result = 31 * result + nome.hashCode();
            result = 31 * result + anoNascimento;
            result = 31 * result + (int)(dataHoje^(dataHoje>>>32));
            result = 31 * result + (java?1:0);
        }
    }
    
    @Test
    public void testComClasse() {
        for (int i = 0; i <= 100000000; i++) {
            HashCode.create().append(nome)
                .append(anoNascimento).append(dataHoje)
                .append(java).hashCode();
        }
    }

}

Em um sistema onde o método hashCode é muito utilizado e/ou possui um cálculo custoso é necessário fazer uma escolha: não utilizar a classe HashCode ou utilizar o conceito de cache e armazenar na própria classe consumidora de HashCode um atributo contendo o hashCode gerado na primeira execução. Isso ajudaria muito, pois somente na primeira vez o hashCode seria gerado, enquanto nas próximas apenas consumido. Cuidado, caches desse tipo não são uma boa alternativa quando se trata de uma classe mutável, já que o hashCode pode estar baseado em atributos que são alterados entre uma solicitação e outra do método hashCode. Desempenho sempre é uma questão delicada.


Considerável ganho de desempenho quando utilizado cache e uma diferença de 3ms quando utilizado a classe HashCode.

public class HashCodeTest {
    
    String nome = "Vinicius Knob";
    int anoNascimento = 1989;
    long dataHoje = Calendar.getInstance().getTimeInMillis();
    boolean java = true;

    @Test
    public void testSemClasse() {
        int cacheResult = 0;
        for (int i = 0; i <= 100000000; i++) {
            if (cacheResult == 0) {
                int result = 17;
                result = 31 * result + nome.hashCode();
                result = 31 * result + anoNascimento;
                result = 31 * result + (int)(dataHoje^(dataHoje>>>32));
                result = 31 * result + (java?1:0);
                cacheResult = result;
            }
        }
    }
    
    @Test
    public void testComClasse() {
        int cacheResult = 0;
        for (int i = 0; i <= 100000000; i++) {
            if (cacheResult == 0) {
                cacheResult = HashCode.create().append(nome)
                    .append(anoNascimento).append(dataHoje)
                    .append(java).hashCode();
            }
        }
    }

}

Conclusão


Essa alternativa atende alguns requisitos para proporcionar flexibilidade e manutenibilidade ao código, porém seria interessante fornecer um atributo para servir como cache em casos onde cálculos exigem muito processamento, mesmo sem utilizar a classe. Alguns críticos podem considerar ela totalmente desnecessária, eu vejo como uma classe encapsuladora de um padrão documentado e que tecnicamente poderia ser seguido dessa forma. Alternativas para essa classe poderia proporcionar melhoria a flexibilidade ou até ao desempenho, uma estrutura diferente com nomes diferentes também é aceitável, mas tudo depende sempre de conhecimento, o que busco incansavelmente.