quarta-feira, 2 de agosto de 2006

[JSF] - DataTables, CommandLink's e CommandButton's

Aqueles que já tiveram o prazer de tentar fazer uma componente commandLink ou commandButtons funcionar dentro de uma componente ''dataTable'' utilizando o escopo request para o managed bean que armazena os dados exibidos pelo dataTable, sabem que não dá. O jeito é mudar o escopo do managed bean para session.

O problema com esta "solução" é que os dados perduram. Exemplificando: imagine que você está implementando um caso de uso que mostra uma lista de entidades que obedecem às restrições impostas por filtros de busca cujos valores são determinados pelo usuário. O comportamento esperado é que, ao acessar a página, não se mostre nenhum valor, e após o usuário ordenar a busca, os elementos sejam obtidos e exibidos. Simples assim. Com a "solução" acima, isto ocorre na primeira vez que o usuário acessa esta página. Porém, dentro da mesma sessão, nas próximas vezes que o usuário acessar a página, ele irá automaticamente visualizar os dados da última busca que ele realizou.

Um pouco de pesquisa, na tentativa de manter o escopo como request, me levou à seguinte descrição de bug (que no final mostrou não ser um bug) - javaserverfaces:issue 69.

Conforme entendi, o problema é que no momento do processamento da fase Apply request values, o managed bean com os dados utilizados pela dataTable ainda não foi inicializado (ele somente será na fase Render response). Desta forma, a decodificação desta componente não funcionará como esperado, e tampouco a decodificação das componentes filhas (incluindo os commandLink's e commandButton's). Por isso, nenhum método de ação associado a estes elementos será executado.

Chegamos então à seguinte conclusão: nossa aplicação só funciona se usarmos escopo session. Mas isto é necessário somente para os dados a serem exibidos pelo dataTable. Com isto, sugiro a seguinte solução:

  1. Crie um managed bean (requestBean) em escopo request para gerenciar os dados não associados ao dataTable, e para gerenciar as ações da sua página
  2. Crie um managed bean (sessionBean) em escopo session somente para armazenar os dados exibidos pelo dataTable
  3. Você deve atribuir um valor vazio para os dados do sessionBean no construtor do requestBean, e com o resultado da busca, sempre que o método que realiza a busca em requestBean for executado

Surge aí outro problema. Como alterar os dados de sessionBean a partir do requestBean? Basta usar o seguinte código dentro do requestBean:


FacesContext context = FacesContext.getCurrentInstance();
context.getApplication().
createValueBinding("#{SessionBean.data}").setValue( context, newData );


Você pode reparar que o EL #{SessionBean.data} é igual ao EL que você usa no seu JSP associado ao atributo value da sua componente dataTable (h:dataTable).

É uma solução trabalhosa. Muito melhor seria se o JSF funcionasse de forma um pouco mais intuitiva. Mas nada é perfeito ...

segunda-feira, 17 de julho de 2006

JBoss WrappedConnection

No JBoss, quando obtemos uma conexão de banco de dados de um Datasource, obtemos um objeto da classe org.jboss.resource.adapter.jdbc.WrappedConnection, que é uma classe que implementa a interface java.sql.Connection.

No entanto, ao utilizar algumas operações específicas da implementação do JDBC da Oracle, me deparei com a seguinte exceção:

java.lang.ClassCastException: org.jboss.resource.adapter.jdbc.WrappedConnection

Pelo que pude entender isto ocorre porque estas operações específicas esperam um objeto conexão do tipo oracle.jdbc.driver.OracleConnection. No entanto, a conexão devolvida pelo Datasource é deste tipo, uma vez que estou usando um banco de dados Oracle (pois é leitor, não iria tentar usar o JDBC da Oracle com outro banco). O que o JBoss faz é encapsular este objeto dentro do objeto WrappedConnection. Desta forma, é possível obter o objeto OracleConnection e utilizar as funcionalidades desejadas do JDBC da Oracle. Para tanto, escrevi o seguinte código:

public class ConnectionUtilities {
   
    /**
     *
     */
    private static final String WRAPPED_CONNECTION_NAME =
        "org.jboss.resource.adapter.jdbc.WrappedConnection";

    /**
     *
     */
    private static final String GET_UNDERLYING_CONNECTION_METHOD =
        "getUnderlyingConnection";

    /**
     * Se a aplicação estiver rodando dentro do JBoss retorna a conexão encapsulada dentro
     * da conexão obtida pelo JBoss. Caso contrário, retorna a própria conexão dada
     *
     * @param conn A conexão com o banco de dados
     * 
     * @return
     */
    public static Connection getUnderlyingConnection(Connection conn) {
        // Variaveis auxiliares
        Connection underlyingConn = conn;
        ClassLoader cl = null;
        Class wrappedConnectionClass = null;
        Method getUnderlyingConnectionMethod = null;
       
        try {
 
            cl = Thread.currentThread().getContextClassLoader();
            wrappedConnectionClass =  cl.loadClass( WRAPPED_CONNECTION_NAME );
            getUnderlyingConnectionMethod = wrappedConnectionClass.getMethod(
                    GET_UNDERLYING_CONNECTION_METHOD, (Class[]) null );
           
            if( wrappedConnectionClass.isAssignableFrom( conn.getClass() ) ) {
                underlyingConn =
                    (Connection) getUnderlyingConnectionMethod.invoke( conn,
                            (Object[]) null );
            }
        } catch (Exception e) {           
        }
       
        return underlyingConn;
    }

}

Note-se que se este código for utilizado fora do ambiente JBoss ele retorna a própria conexão dada como parâmetro. Desta forma consigo utilizar o mesmo código no ambiente de testes que configurei no Eclipse, e no ambiente de produção com o JBoss.

quinta-feira, 27 de abril de 2006

Código de alta qualidade

Na minha vida como desenvolvedor já tive a oportunidade de trabalhar com vários outros desenvolvedores, utilizando diferentes linguagens, diferentes ferramentas, diferentes arquiteturas ... no entanto, uma coisa que é comum em todas estas experiências, diz respeito com integração de códigos.

Modelar um software, e dividir a implementação entre vários desenvolvedores é bastante comum. Na teoria, agiliza o desenvolvimento. Cada um implementa sua parte, realiza seus testes, acha tudo perfeito, e quando vai integrar, tudo começa a dar errado. E daí quando você tem que mexer no código que outra pessoa fez, daí é que tudo vai pro espaço.

Para minimizar estes problemas, é bom adotar algumas práticas de programação e desenvolvimento. Definir bons testes de unidade antes de iniciar a implementação, utilizar códigos de programação, etc ... Tendo em vista este problema, um bom artigo é o post "Producing and maintaining high-quality code", do blog Ozone. O autor lista 10 dicas sobre como escrever bons códigos, e em decorrência, gerar bons softwares.

Uma das dicas interessantes é a de número 3 - Talk to your cardboard friend, que eu conhecia como "Técnica do ursinho". Esta técnica aprendi através de um professor, que relatou que um outro professor que lecionava na universidade em que ele fez doutorado tinha um ursinho de pelúcia que ele levava nas aulas de laboratório. Toda vez que um aluno tinha uma dúvida, ele tinha que explicar o problema pro ursinho. Com isso, boa parte dos alunos conseguiam enxergar o problema, só explicando o mesmo pro ursinho.

Voltando ao artigo, é bastante interessante, e pode ser bastante útil. O autor inclusive sugere ferramentas que podem facilitar a vida dos desenvolvedores. E você, tem mais alguma dica para compartilhar? Dê seus comentários.

quarta-feira, 19 de abril de 2006

AjaxXLS

Meus posts estão ficando cada vez mais repetitivos. Na verdade ando sem muito tempo para colocar coisas interessantes aqui, apesar de estar estudando bastante coisa no momento. Mas só pra alimentar o desejo incontrolável de meu público fiel por um novo post, vou falar sobre a última da galera do ajaxLaunch.

A nova aplicação é o AjaxXLS. Diferente das outras ferramentas lançadas por esse grupo, esta funciona apenas como um visualizador, o que devo confessar me deixou um pouco desapontado. O que ele faz é abrir planilhas no formato xls, e promete manter as fórmulas, backgrounds e bordas dos arquivos. No entanto, no primeiro arquivo que fui abrir, com fórmulas, cores de linhas alternadas e formatação de fontes diversas, o resultado foi horrível. Ele apenas conseguiu mostar parte da primeira linha. Tentei depois com um arquivo sem fórmulas, e o resultado foi melhor.

Das três ferramentas que avaliei deste grupo, esta é com certeza a de menor qualidade. Com certeza eles devem prover melhorias, e espero façam com que a qualidade desta ferramenta se equipare à das demais.

quarta-feira, 5 de abril de 2006

AjaxSketch

No meu último post falei aqui sobre o AjaxWrite. O mesmo grupo que lançou esta ferramenta lançou o AjaxSketch, uma ferramenta para criar diagramas, fluxogramas, desenhos a mão livre. Tudo baseado em ajax, rodando em browsers Firefox 1.5 ou mais novos.

A ferramenta é bastante simples, e não tem o apelo de um processador de texto. Mas é interessante. Ele utiliza o formato SVG, permitindo que os arquivos gerados por esta ferramenta sejam visualizados diretamente por ferramentas como Microsoft Visio, Adobe Illustrator, Macromedia Freehand, entre outros.

Se você um dia quiser criar um diagrama básico, e tiver somente um browser à mão, lembre-se desta ferramenta.