terça-feira, 20 de dezembro de 2011

Geração de ID's para Oracle e MySql usando Hibernate


Aqui você tem exemplos de geração automática de ID's para banco de dados Oracle e MySql usando Hibernate.

Oracle

...

@Entity
@Table(name = "grupo")
public class Grupo implements GenericModel {


@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "GRUPO_ID_SEQ")
@SequenceGenerator(name = "GRUPO_ID_SEQ", sequenceName = "GRUPO_ID_SEQ", allocationSize = 1)
@Column(nullable=false)
private Long id_grupo;

...


A sequence GRUPO_ID_SEQ deve existir no banco de dados.

Considerando que MySql não tem sequences, se você tentar usar o código acima com MySql você terá a  exceção abaixo em tempo de execução:

Caused by: org.hibernate.MappingException: Dialect does not support sequences
at org.hibernate.dialect.Dialect.getSequenceNextValString(Dialect.java:619)
at org.hibernate.id.SequenceGenerator.configure(SequenceGenerator.java:88)
at org.hibernate.id.SequenceHiLoGenerator.configure(SequenceHiLoGenerator.java:66)
at org.hibernate.id.IdentifierGeneratorFactory.create(IdentifierGeneratorFactory.java:127)


MySQL

...
@Entity
@Table(name = "grupo")
public class Grupo implements GenericModel {


@Id
@GeneratedValue
@Column(nullable=false)
private Long id_grupo;

...


O campo id_grupo deve ser marcado como auto incremento no MySql.

segunda-feira, 12 de dezembro de 2011

PASSEI: 1Z0-894 Oracle Certified Expert Java Platform, Enterprise Edition 6 JavaServer Pages and Servlet Developer

Fiz a prova no dia 09/12 e consegui passar! Raspando, mas passei.

Estava tirando 70% nos Mocks e esperava passar com uma pontuação de 75% ou 80%, mas a prova foi mais difícil do que eu esperava e passei com 68%.

Como havia postado 22/09, eu baseei meus estudos no Mock e Study Guide da EPractize Labs, porque eu já havia lido o livro Head First J2EE1.4 da Katy Sierra algumas vezes em outras ocasiões. Também dei uma lida na spec de Servlet 3.0.

Eu não recomendo a EPractize Labs. O Study Guide é muito superficial e o Mock tem muitos erros. Além disso o Mock não está coerente com a prova real. A prova não cobra quase nada de Custom Tags e cobra muito da spec de Servlet 3.0, mas o Mock está ao contrário.

O que eu acredito que me salvou foi a página do Piotr (http://piotrnowicki.com/2011/03/jee-6-scwcd-mock-questions/) que tem 67 questões focadas na especificação de Servlet 3.0 e também o Mock da Enthuware (http://enthuware.com/index.php/mock-exams/oracle-certified-expert/oce-jsp-servlet-mock-questions).

Esse Mock é mais barato e a qualidade dele é infinitamente maior. A prova disso é que além de ser 100% Test Pass Garantee, eles devolvem o dinheiro caso você encontre 3 erros. Muitas questões do exame foram bem parecidas com as do Mock.

A minha dica para quem for se preparar para essa prova é:

* Estudar o livro Head First Servlets & JSP, segunda edição (JEE5): http://shop.oreilly.com/product/9780596516680.do?green=25526262438&cmp=af-mybuy-9780596516680.IP
* Estudar a Spec JSR-315 de Servlets 3.0: http://jcp.org/aboutJava/communityprocess/mrel/jsr315/index.html
* Responder as questões do Piotr
* Fazer o Mock do Enthuware

Seguindo esses passos com tempo, com certeza você se sairá melhor do que eu :-)

Bons estudos!

quinta-feira, 10 de novembro de 2011

Telnet no Windows Vista


O Windows Vista tem telnet client sim! Só não está habilitado, afinal de contas, por que as vovózinhas iriam querer essa funcionalidade?

Para habilitar, vá no Menu Iniciar, clique em "Executar...", digite "optionalfeatures" (sem aspas) e clique OK.

A janela 
"Windows Features" vai aparecer, então você pode habilitar o telnet client. Aproveite para habilitar uns jogos também :-). Clique OK e espere muitos minutos.

Precisa reiniciar para se divertir com o telnet.

terça-feira, 1 de novembro de 2011

Como encontrar a tabela de UtcTimeOffsetCode em arquivos TAP3


Uma das informações nos registros Moc (Mobile Originated Calls) e Mtc (Mobile Terminated Calls) é o Call Event Start Time Stamp.

O Call Event Start Time Stamp é formado pelo Local Time Stamp (YYYYMMDDHHMMSS) e pelo Utc Time Offset Code.

Utc Time Offset Code (5F-81-68) pode ser qualquer número inteiro de 0 a 99 e com esta informação, você será capaz de descobrir o UTC Time Offset (5F-81-67).



O problema é esta informação não é padronizado para todos os arquivos TAP, é uma informação auto-contida nos arquivos TAP3, em outra seção. Em outras palavras, cada arquivo TAP3 tem o sua própria lista de Utc Time Offset Code mapeada para um UTC Offset real.

Esta tabela é chamada de Utc Time Offset Info e está localizada na seção Network Information. A sessão Utc Time Offset Info pode ter um ou mais Utc Time Offset Definition e cada Utc Time Offset Definition tem seu o mapeamento entre o Utc Time Offset Code e o Utc Time Offset.


No exemplo das figuras, o código 65 foi mapeado para o UTC Offset -05:00:

O TAP3 foi projetado desta forma para minimizar a quantidade de dados transferidos e para evitar a repetição de informações idênticas no nível de chamada / evento.

Dica:
Programas para trabalhar com arquivos TAP3:
TAP3 Editor (http://www.combil.com/tap3ed2.htm): Usado para ver os registros do TAP3 de forma estruturada
ASN1VE (http://www.obj-sys.com/asn1-viewer.php): Usado para ver o conteúdo binário dos dados ASN.1

quinta-feira, 20 de outubro de 2011

Log4j mistura logs entre as aplicações no Weblogic


Tenho um Web Service JWS executado em Weblogic 10.2 e seus logs estavam sendo misturados com outra aplicação web rodando no mesmo servidor.

Eu pensei que as aplicações foram totalmente independentes dentro do servidor, mas elas não são. Elas compartilham alguns classloaders. Veja imagem abaixo:



Esse problema ocorre porque o jog4j.jar é compartilhado entre as aplicações e isto ocorre porque ele é buscado do mesmo classloader.

Para resolver este problema, é necessário que cada aplicativo tenha o seu próprio log4j.jar dentro do .war. (ou .ear quando aplicável). É importante que todas as aplicações tenham seu próprio log4j. Se um deles não tiver, o problema vai continuar.

Além de ter o log4j.jar, também é necessário editar o weblogic-application.xml para avisar o Weblogic para  usar as classes do log4j do classloader da aplicação.

Segue um exemplo de weblogic-application.xml:

<?xml version='1.0' encoding='UTF-8'?>
<weblogic-application xmlns="http://www.bea.com/ns/weblogic/90" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<prefer-application-packages>
   <package-name>org.apache.log4j.*</package-name>
</prefer-application-packages>
</weblogic-application>


Se você estiver usando ant para construir o seu webservice JWS no Weblogic com a task jwsc, segue um trecho de build.xml que você pode usar para colocar o log4j no .war e usar um weblogic-application.xml personalizado.

No .war o log4j.jar deve ser colocado na pasta WEB-INF/lib e no .ear o weblogic-application.xml deve ser colocado na pasta META-INF.

<target name="jwsc" description="build web service">
  
    <delete dir="${build.dir}"/>
    <mkdir dir="${build.dir}"/>  
  
    <jwsc
        srcdir="${webapp.dir}"
        destdir="${build.dir}" 
     verbose="on" debug="on"
     keepGenerated="no" >

     <jws file="${jwsc.file}"
           compiledWsdl="${jwsc.jws.compiledWsdl}"
           contextPath="${jwsc.jws.contextPath}" 
           type="JAXWS" explode="false" >
</jws>
    </jwsc>
  
    <war destfile="${war.built}" update="true" >
        <fileset dir="${webapp.dir}">
           <include name="**/*.jar" />
   </fileset>
    </war>

    <copy file="${service.src}/resource/weblogic-application.xml" todir="${build.dir}/META-INF/" overwrite="true" />
  
 </target>



É importante que ${war.built} aponte para o ,war e o ${webapp.dir} aponte para a pasta com o fonte do webservice que possui pasta WEB-INF, que possui pasta lib, que possui log4j.jar.


Links:
http://download.oracle.com/docs/cd/E12840_01/wls/docs103/programming/classloading.html
https://forums.oracle.com/forums/thread.jspa?threadID=689458
http://www.coderanch.com/t/554020/Web-Services/java/adding-jar-files-building-war
http://ant.apache.org/manual/Tasks/war.html

quarta-feira, 19 de outubro de 2011

Por que o log4j não está logando?


Recentemente tive um problema com o mecanismo de log em um sistema que tive que dar manutenção.


Ele simplesmente estava ignorando a configuração log4j.properties e logava as mensagens com nível INFO.


Depois de algum tempo eu descobri que ele estava usando common-logging ao invés do log4j puro.


Não há nenhum problema em usar o commons-logging, ela funciona bem. O problema real era que apenas o commons-logging-api.jar e o log4j.jar foram incluídos no classpath. Estava faltando o commons-logging.jar.


Para suportar o log4j, o commos-logging precisa de dois jars no classpath: commons-logging e commons-logging-api.


Depois de adicionar o commons-logging.jar no classpath, o log4j.properties começou a ser lido e respeitado.


Leia mais sobre commons-logging aqui: http://commons.apache.org/logging/guide.html#Jars Included in the Standard Distribution

quinta-feira, 22 de setembro de 2011

1Z0-894 Oracle Certified Expert Java Platform, Enterprise Edition 6 JavaServer Pages and Servlet Developer

Comecei a me preparar para certificação de desenvolvimento Java para Web, antiga SCWCD - Sun Certified Web Components Developer.

Na versão mais nova dessa certificação, e já no mundo Oracle, o código dessa certificação é 1Z0-894, e o nome é Oracle Certified Expert, Java Platform, Enterprise Edition 6 JavaServer Pages and Servlet Developer.

Você encontrará mais detalhes sobre essa prova no site da Oracle: http://education.oracle.com/pls/web_prod-plq-dad/db_pages.getpage?page_id=41&p_exam_id=1Z0_894

O site da EPractize Labs também tem informações interessantes, inclusive um simulador de quanto tempo você vai precisar para se preparar para a prova: http://www.epractizelabs.com/blog2/?p=106

Como essa prova é relativamente nova, e eu já havia lido o livro Head First Servlets & JSP JEE 1.4 por duas vezes, resolvi me preparar somente com o Study Guide e o Mock Exam do EPractize Labs:
http://www.epractizelabs.com/certification/sun/oce-jsp-servlet-exam-6.html

Esse material custa $40.5 dólares, mas a EPractize Labs garante o dinheiro de volta caso não passe na prova.

Esse Study Guide tem alguns erros de Ctlr-C/Ctrl-V, vários typos e o conteúdo é muito superficial, mas eu pretendo preencher a lacuna com pequisas na internet.

Também montei um projeto no Eclipse para ir fazendo na prática o que eu aprendo no Study Guide.

O meu objetivo é fazer a prova na primeira semana de Dezembro/2011, tomara que dê tempo!

Depois em conto como me saí.

Se você tiver dicas ou dúvidas sobre essa certificação, compartilhe comentando este post.

--
PS: Confira o resultado http://pontodebug.blogspot.com/2011/12/passei-1z0-894-oracle-certified-expert.html

quarta-feira, 3 de agosto de 2011

Função Oracle PL/SQL para testar se uma string representa um número: isNumber ou isNumeric

TAGs: Oracle, SQL, PL/SQL, isNumber, isNumeric

Não existe uma função para testar se o conteúdo de uma string representa um valor numérico, mas existe um workaround.

LENGTH(TRIM(TRANSLATE(string1, ' +-.0123456789', ' ')))

Essa função vai retornar null se o valor for numérico, assim você pode testar com "is null" em uma cláusula where. Por exemplo:

select * from tabela where LENGTH(TRIM(TRANSLATE(campoString, ' +-.0123456789', ' '))) is null

A função translate troca os dígitos por espaços '  '. A função trim remove os espaços. A função length retorna o tamanho da string. Se a string não for numérica, o tamanho será positivo, caso seja numérica, length retornará null.

Fonte: http://www.techonthenet.com/oracle/questions/isnumeric.php

quinta-feira, 9 de junho de 2011

Comandos do vi

    Sintaxe para executar o vi:
    $ vi nome_do_arquivo
    
    Uma vez carregado o arquivo, você pode navegar com as teclas direcionais (up, down, left, right), mas para editar o arquivo é necessário usar os comandos abaixo:
    Observação: Use o ESC para voltar ao modo de comando.
    Comandos básicos de inserção de texto:
    iInsere texto antes do cursor
    aInsere texto depois do cursor
    rInsere texto no início da linha onde se encontra o cursor
    AInsere texto no final da linha onde se encontra o cursor
    oAdiciona linha abaixo da linha atual
    OAdiciona linha acima da linha atual
    Ctrl + hApaga o último caracter
    Comandos básicos de movimentação:
    Ctrl+fMove o cursor para a proxima tela
    Ctrl+bMove o cursor para a tela anterior
    HMove o cursor para a primeira linha da tela
    MMove o cursor para o meio da tela
    LMove o cursor para a ultima linha da tela
    hMove o cursor um caracter a esquerda
    jMove o cursor para a proxima linha
    kMove o cursor para linha anterior
    lMove o cursor um caracter a direita
    wMove o cursor para o inicio da proxima palavra (Ignora a pontuacao)
    WMove o cursor para o inicio da proxima palavra (Nao ignora a pontuacao)
    bMove o cursor para o inicio da palavra anterior (Ignora a pontuacao)
    BMove o cursor para o inicio da palavra anterior (Nao ignora a pontuacao
    0Move o cursor para o inicio da linha atual
    ^Move o cursor para o primeiro caracter nao branco da linha atual
    $Move o cursor para o final da linha atual
    nGMove o cursor para a linha n
    GMove o cursor para a ultima linha do arquivo
    Comandos basicos para localizar texto:
    /palavraBusca pela palavra ou caracter em todo o texto
    ?palavraMove o cursor para a ocorrencia anterior da palavra
    nRepete o ultimo comando / ou ?
    NRepete o ultimo comando / ou ? , na direcao reversa
    Ctrl+gMostra o nome do arquivo, o numero da linha corrente e o total de linhas
    Comandos basicos para alteracao de texto:
    xDeleta o caracter que esta sob o cursor
    dwDeleta a palavra, da posicao atual do cursor ate o final
    ddDeleta a linha atual
    DDeleta a linha a partir da posicao atual do cursor ate o final
    rxSubstitui o caracter sob o cursor pelo especificado em x(é opcional indicar o caracter)
    RxSubstitui a palavra sob o cursor pela palavra indicada em x
    uDesfaz a ultima modificacao
    UDesfaz todas as modificacoes feitas na linha atual
    JUne a linha corrente a proxima
    s:/palavra1/palavra2Substitui a primeira ocorrencia de "palavra1" por "palavra2"
    Comandos para salvar o texto:
    :wqSalva o arquivo e sai do editor
    :w nome_do_arquivoSalva o arquivo corrente com o nome especificado
    :w! nome_do_arquivoSalva o arquivo corrente no arquivo especificado
    :qSai do editor
    :q!Sai do editor sem salvar as alterações realizadas
        Exemplo para abrir um arquivo, adicionar um texto e salvar:
        1 - digite no prompt: vi <nome_do_arquivo>
        2 - tecle "i", quando o cursor estiver no ponto desejado
        3 - digite o texto
        4 - tecle "ESC"
        5 - digite :wq

    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)