quarta-feira, 12 de janeiro de 2011

Como fazer uma tabela displaytags não ser exibida quando a página é carregada

Tags: JSP - Struts 2 - AJAX - struts-dojo-tags

Considerando que você tenha uma tela com campos de filtragem, uma tabela (usando displaytags e AJAX) com os resultados da busca e essa busca seja relacionada a uma tabela com muitos registros.

Quando a tela for acessada, como nenhum filtro foi especificado, todos os registros da base de dados vão ser mostrados na tabela e isso pode demorar muito.

Para evitar esse problema você pode mostrar a tabela vazia e deixar parar mostrar os resultados somente depois que o botão de Busca seja acionado.

Na verdade a solução deste problema não está no diplaytags, mas sim na tag "div" do struts-dojo-tags onde a tabela é apresentada.

A tag fica assim:


<sx:div showLoadingText="true" 
        id="gridDivId" 
        href="seusistema/SuaAction" 
        theme="ajax"
        listenTopics="show_grid" 
        formId="frm_demo" 
        executeScripts="true" 
        preload="false">
   Preencha os campos do filtro e depois clique no botão Buscar 
</sx:div>    


O pulo do gato aqui é a propriedade "preload", que tem o valor default true. Quando ela é true, ela aciona imediatamente a ajax linkado com a tabela displaytags que realiza a busca.

O texto dentro da tag div será apresentado no lugar reservado à tabela quando a tela for acessada.

Referência:
[1] http://struts.apache.org/2.0.14/docs/dojo-div.html

terça-feira, 11 de janeiro de 2011

Como limitar o número de registros retornados em uma consulta SQL

Tags: SQL, Ansi SQL, TOP, LIMIT, ROWNUM, Oracle, SQL Server

Não existe uma instrução SQL padronizada para limitar o número de registros retornados em uma consulta, ou seja, cada fornecedor implementa essa funcionalidade do seu jeito.

Veja um resumo de como fazer isso para alguns fabricantes:


DB2 -- select * from table fetch first 10 rows only 
Informix, InterBase/Firebird, SKIP  -- select first 10 * from table 
Microsoft SQL Server and Access -- select top 10 * from table 
MySQL, PostgreSQL, SQLite, HSQL/H2 -- select * from table limit 10 
Oracle -- select * from table where rownum <= 10




Referências:

http://stackoverflow.com/questions/595123/is-there-an-ansi-sql-alternative-to-the-mysql-limit-keyword
http://www.macoratti.net/d250102.htm
http://www.dougboude.com/blog/1/2006/06/Equivalent-of-SQL-TOP-X-in-Oracle.cfm

sexta-feira, 7 de janeiro de 2011

Como externalizar o persistence.xml

Tags: Java 6 - JEE - Spring 2.5 - Hinernate 3.0

No persistence.xml é possível configurar, entre outras coisas, a conexão com a base de dados.

Quando o sistema é entregue ao cliente em um jar ou war, não existe uma maneira trivial de alterar as informações da base de dados, como a string de conexão, o username e o password.

Para fazer isso o cliente precisaria abrir o jar/war, alterar o persistence.xml e remontar o archive. Como nem sempre o cliente tem um time que saiba fazer isso, pode ser que você queira deixar o persistence.xml fora da pasta META-INF do seu projeto, por exemplo, em um folder de configuração do sistema em qualquer lugar do file system.

Abaixo segue o trecho a ser configurado no applicationContext.xml:


<beans ...>


    <bean id="propertyPlaceholder" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
        <property name="systemPropertiesModeName" value="SYSTEM_PROPERTIES_MODE_OVERRIDE"/>
        <property name="ignoreResourceNotFound" value="true"/>
        <property name="locations">
            <list>
                <value>file:///${CONF_FOLDER}/dataSource.properties</value>
            </list>
        </property>
    </bean>
    
    <bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
       <property name="persistenceXmlLocation" value="file:///${persistence.path}"/>
       <property name="persistenceUnitName" value="persistence-unit"/>
    </bean>
    
    <bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
        <property name="entityManagerFactory" ref="entityManagerFactory" />
    </bean>    
    
    <tx:annotation-driven transaction-manager="transactionManager" />
    
    <bean class="org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor"/>
    
    <bean class="org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor"/>
 
    <context:annotation-config />
    
    <context:component-scan base-package="br.com.seupackage.*"/>


</beans>



O pulo do gato aqui é a propriedade persistenceXmlLocation do LocalContainerEntityManagerFactoryBean. Com ela você pode especificar que o persistence.xml estará em qualquer lugar do .jar ou do file system [1].

Para não deixar o caminho do persistence.xml hardcoded e como não é possível usar variável de ambiente nessa propriedade, é possível utilizar o PropertyPlaceholderConfigurer para configurar esse path.


O arquivo dataSource.properties, que está no folder reprensentado pela variável de ambiente ${CONF_FOLDER}, tem a propriedade persistence.path com o caminho absoluto do persistence.xml.


O problema estaria resolvido aqui se não fosse um efeito colateral de mudar o persistence.xml de lugar. Quando o persistence.xml não está dentro do jar, o PU root path muda para o jar que iniciou o sistema.

Se o ponto de entrada do sistema é o jar que possuía o persistence.xml (java -jar seuSistema.jar), não tem problemas.

Caso o jar ponto de entrada do sistema chame outro jar que é o que possuía o persistence.xml, aí você terá que fazer uma modificação no persistence.xml

Um exemplo dessa arquiterura é:
projeto_gui.jar       - ponto de entrada do sistema
projeto_model.jar  - possui o applicationContext e o persistence

Veja a modificação no persistence.xml:


<persistence ...>


<persistence-unit name='persistence-unit'>


<provider>org.hibernate.ejb.HibernatePersistence</provider>
        
        <jar-file>file:///C:/seusistema/lib/projeto_model.jar</jar-file>
         
<properties>
...


            <property name="hibernate.connection.provider_class"
                    value="org.hibernate.connection.C3P0ConnectionProvider" />            
...
            <property name="hibernate.connection.url" value="jdbc:oracle:thin:@192.168.0.2:1521:base" />
    <property name="hibernate.connection.username" value="user" />  
    <property name="hibernate.connection.password" value="password" />  
</properties>


</persistence-unit>


</persistence>


A tag <jar-file> foi adicionada para informar que o PU root path (o caminho que este persistence unit deve procurar as classes anotadas como Entity) é o jar que possuía o persistence.xml antes desta alteração.


Referência:

[1] LocalContainerEntityManagerFactoryBean: http://static.springsource.org/spring/docs/2.0.x/api/org/springframework/orm/jpa/LocalContainerEntityManagerFactoryBean.html#setPersistenceXmlLocation(java.lang.String)