Postado por: evandropaes | Julho 30, 2008

Chefe ou Lider: Como um GP deve ser?

Autor: Diego Pacheco

Fonte: http://diego-pacheco.blogspot.com/2008/07/chefe-ou-lider-como-um-gp-deve-ser.html

Terça-feira, 22 de Julho de 2008

Acredito que nos (profissionais de TI) já trabalhamos ou ainda estamos trabalhando com “chefes”. Será que a disciplina de Gestão de Projeto ainda é utilizada de maneira imprópria mesmo nos dias de hoje? Sim, de fato é. O GP (Gerente de Projetos) tem um papel crucial no sucesso de um projeto de software.

Gerente ou Dono do Projeto?

Essa questão é mais abrangente, na verdade o ponto é “Gerente ou Dono”. Isso se aplica para redes de computadores também. Quem nunca ouviu alguem dizer um Administrador de redes dizendo “É na MINHA REDE ninguém instala programas que não são padrões”? Na verdade esse tipo de “coisa” nos escutamos de gerentes de projetos também.

O Gerente deve gerenciar o projeto isso significa manter o time na linha, servir como um motivador e facilitador da equipe, assim ele será um gerente não um dono. O PMI “diz” que o GP deve ouvir os “Subject Matters”, ou seja, especialistas e com as informações do mesmo tomar as devidas decisões que devem ser todas.

O Anti-Pattern: Gerente é quem decide o que e como deve ser feito

Por incrível que parece, já trabalhei em projeto em que o suposto GP se “metia” com a suposta “Arquitetura” ia em reuniões, expressava sentimentos sobre UML. Não tenho nada contra um gerente que conheça mais a fundo o desenvolvimento até por que ele pode ter sido um desenvolvedor em algum dia. Porem não podemos permitir que um “suposto” GP decida o rumo das coisas.

Gerenciamento de Conflitos

Um bom gerente deve saber como lidar com conflitos tanto internos quanto externos. Quem já não trabalhou com gerentes que simplesmente ignoravam os conflitos e usavam o velho anti-pattrern “Empurrar com a Barriga”? Eu infelizmente já vi alguns. Um bom gerente deve resolver os conflitos quando eles ocorrerem, tratando o problema de maneira efetiva para que no futuro o projeto não vire uma grande bola de lodo emocional onde todos se odeiam e o software não sai.

Muitas vezes é preciso que o GP tenha aquele principio do XP a Coragem. É necessário coragem para realizar uma correção de rumo e mostrar a um colaborador que ele está errado e que ele deve refletir sobre o ocorrido para o bem dele e da equipe. Felizmente eu já trabalhei com profissionais que tinham de fato essa habilidade.

Seu GP é um Lider?

Eu já tive o privilegio de trabalhar com GPs que eram lideres, mas foram pouquíssimos, na verdade dá pra contar com metade dos dedos da mão! Um lider consegue melhorar a qualidade do trabalhos dos membros da equipe e manter o foco da equipe de forma que as pessoas respeitem ele. Isso ocorre por que esse tipo de atitude gera confiança de parte dos membros da equipe para o GP, assim as pessoas seguem os conselhos e as orientações do GP e ele consegue atingir os seus propósitos com muito mais facilidade.

Seu GP pode ser um Arquiteto?

Certamente. O processo OpenUp recomenda que em projetos pequenos o GP seja o Arquiteto. Não se engane isso é possível, o verdadeiro arquiteto é um lider nato. Infelizmente o Kent Back(autor do XP) acho desaconselhável um arquiteto exercer uma função de GP(no XP é o Coach), eu discordo da opinião dele, de fato ele não deve ter conhecido um arquiteto de verdade, eu sinceramente não conheci muitos também :)

Gerente de Projetos: Afunda Projetos

Isso é umn fato. Quanto maior o projeto e quanto mais risco o mesmo tem, mais experiencia o GP deve possuir. Infelizmente aqui no Brasil muitas vezes o GP é o Filho do Dono da empresa, ou é uma pessoa que já está a muitos anos na empresa e não tinha mais como evoluir, ai do nada o cara vira “Gerente de Projetos” tadamm! Bom ai está feita a merda.

Para ser um bom GP, o cara deve ser um Lider nato, deve ter tato com as pessoas, e se a pessoa não tem esses skills não adianta. Isso vai só adicionar mais riscos ao projeto.

E o toten do PMI: “Plan to Work, Work to Plan”?

Latímavel. Esse slogan veio nas primeiras versões do PMI, isso remete aquela velha ideia do projeto em cascata. Cascata é um exelente metodologia, mas não pra o desenvolvimento de software. Existem coisas legáis no PMI, mas mesmo assim existem coisas do estilo “Cascata”, temos que dar um colher pro PMI, por que foi criado para a engenharia, exemplo: Criação de pontes. O fato é que a nossa área é muito nova, isso complica um pouco mais as coisas.

Planejar necessáriamente é ruim? Não é. O que ocorre é que existe um momento correto de se estimar, lembre-se do cone de incertezas. Como esse post é mais focado nas questões de GP, eu não posso deixar de falar disso.

Como mensurar o Progresso?

Olha pessoal acho que isso é unaneme. É algo do tipo Desenvolvimento Iterativo Incremental, mas mesmo assim tenho que falar. É de fato históricamente errado mensurar um projeto da seguinte forma:

Análise: 85%
Desenv: 49%
Testes: 25%
Implant: 5%

ou ainda pior:

Análise: 85%
Desenv: 0%
Testes: 0%
Implant: 0%

Isso me diz que estamos utilizando o modelo em Cascata. Por que é simplismente impossível ter 85% de análise e não ter nada de código e testes. De fato isso pode ser que não se reflita em uma cascata em 100% porem estamos vendo uma herança da cascata o Anti-Pattern Big Specs Up to Front.

Outro ponto chave é: Mensure apartir do que foi entregue. Bom isso está escrito no RUP e no cerno dos métodos ágeis. Infelismente eu já participei de um projeto que os caras mensuravam da forma errada que eu mostra a cima em vermelho. O que isso gerou? O projeto ficou 4 meses em 99% e esse 1% nunca chegava.

Esse é o problema desse tipo de mensuramento. Ele é falso e dá uma falsa ilusão de progresso. Essa questão está liaga com a falta de priorização e os problemas de se entregar software que não agrega valor ao negócio.

Abraços e Até a Próxima.

Postado por: evandropaes | Junho 20, 2008

Principais Atalhos da IDE Eclipse

Conteudo retirado do site: http://robsonmedeiros.wordpress.com/2008/06/20/principais-atalhos-da-ide-eclipse/

Alguns dos principais atalhos da IDE Eclipse.

Busca

  • Ctrl+Shift+R
    Busca e abre rapidamente qualquer item do projeto, seja ele uma classe, arquivo XML, arquivo de properties, bytecode etc.
  • Ctrl+T
    Mostra a hierarquia da classe atual, permitindo abrir rapidamente qualquer classe da hierarquia.
  • Ctrl+H
    Abre a janela de pesquisa nos arquivos do workspace. Nela é possível procurar tanto por trechos textuais nos arquivos, quanto por referências a elementos da linguagem como tipos, métodos, pacotes, atributos etc.
  • Ctrl+J
    Busca incremental no arquivo aberto. O cursor é posicionado no trecho de código correspondente à medida em que o programador digita o termo de pesquisa.
  • Ctrl+Alt+G
    Pesquisa no workspace por todas as ocorrências do elemento sobre o qual o cursor está posicionado.

Navegação no código

  • Alt+Left
    Volta para a última posição editada.
  • Alt+Right
    Avança para a próxima posição editada.
  • Ctrl+O
    Mostra a estrutura (outline) do arquivo que está sendo editado e permite navegar até declaração selecionada.
  • Ctrl+G
    Localiza a declaração da classe, interface, atributo ou método selecionado.
  • Crtl+Shift+G
    Localiza todas as referências à classe, interface, atributo ou método selecionado existentes no workspace.
  • Ctrl+3
    Navegação rápida. Navega entre todos os itens abertos em todas as views e perspectivas abertas no momento. Novo no Eclipse 3.3 .

Organização do código

  • Crtl+Shift+F
    Formata automaticamente o trecho de código selecionado de acordo com as configurações definidas em Window > Preferences > Java > Code Style > Formatter
  • Crtl+Shift+O
    Organiza os imports do arquivo aberto, removendo as declarações desnecessárias.
  • Alt+(Seta para cima ou para baixo)
    Move a linha atual para cima ou para baixo.
  • Alt+Shift + (Seta para cima ou baixo)
    Copia a linha atual para cima ou para baixo

Depuração

  • Ctrl+1
    Invoca a funcionalidade de reparo rápido (quick fix) quando o compilador acusa algum erro. O reparo rápido consiste em um pop-up com uma lista de sugestões de modificação que são aplicadas automaticamente ao selecionar.
  • Ctrl+Shift+I
    Inspeciona o valor das variáveis enquanto ocorre a depuração. Disponível apenas na perspectiva Debug.

Refactoring

  • Alt+Shift+R
    Renomeia o elemento.
  • Alt+Shift+L
    Extrair para variável local. Atribui a expressão selecionada a uma váriavel.
  • Alt+Shift+M
    Extrair método. Cria um novo método contendo o trecho de código selecionado.

Configuração

  • Ctrl+Shift+L
    Mostra a lista de atalhos de teclado.
  • Ctrl+Shift+L duas vezes
    Abre a tela de personalização de atalhos de teclado.
Postado por: evandropaes | Junho 20, 2008

Protegendo o seu código java da engenharia reversa

Fonte: http://erkobridee.com/2008/06/19/protegendo-o-seu-cdigo-java-da-engenharia-reversa/

Publicado por Erko Bridee em 19/06/2008 18:02 pm | sobre: Desenvolvimento, JAVA, Segurança, Tutorial, tilidade

Caso você seja um desenvolvedor de aplicações java, é importante compreender que os arquivos binários .class do Java podem ser facilmente descompilados em uma engenharia reversa. Neste post iremos ver como um arquivo .class Java é revertido para um fonte Java e como proteger o seu código disto.

O código fonte java é compilado para um arquivo ,class, o qual possui o código binário. A máquina virtual Java (JVM) precisa apenas desse arquivo para executar a sua aplicação. O problema é que este arquivo .class pode ser facilmente descompilado, recuperando o seu código fonte original, utilizando alguma ferramenta para descompilação do .class e caso você procure no Google irá perceber que não é dificil encontrar uma ferramenta para fazer exatamente isto.

A melhor solução para previnir a engenharia reversa é ofuscar o nosso arquivo .class, o que irá dificultar e muito a engenharia versa. De acordo com o dicionário ofuscar que dizer “tornar algo obscuro, não compreensível“. E é exatamente isto o que muitas ferramentas de ofuscar faz, como será explicado a seguir.

Descompilando um arquivo .class Java

Antes de compreender como um ofuscar um código java, vamos tentar compreender como alguem consegue realziar uma engenharia reversa da sua aplicação java. A seguir 3 passos para explicar como um arquivo .class é recuperado desse o código fonte java original, usando técnicas de engenharia reversa.

1. Crie um HelloWorld.java como o código abaixo:

  1. public class HelloWorld {  
  2.     public static void main (String args[]) {  
  3.         String userMessage = “Hello World!”;  
  4.         int userCount = 100;  
  5.         userCount = userCount + 1;  
  6.         System.out.println(userMessage);  
  7.         System.out.println(userCount);  
  8.     }  
  9. }  
public class HelloWorld {
    public static void main (String args[]) {
        String userMessage = “Hello World!”;
        int userCount = 100;
        userCount = userCount + 1;
        System.out.println(userMessage);
        System.out.println(userCount);
    }
}

2. Compile o programa HelloWorld.java e execute, algo como o feito a seguir:

$ javac HelloWorld.java
$ java HelloWorld
Hello World!
101

O arquivo Java .class contém apenas o byte code. caso você tente ver o conteúdo do arquivo .class, irá notar que é algo que humanamente não é compreensível, como o que é mostrado abaixo:

$ vi HelloWorld.class
Ãþº¾^@^@^@2^@
^@^G^@^P^H^@^Q  ^@^R^@^S
^@^T^@^V^G^@^W^G^@^X^A^@^F<init>^A^@^C()V^A^@^DCode^A^@^OLineNumberTable
^A^@^Dmain^A^@^V([Ljava/lang/String;)V^A^@
SourceFile^A^@^OHelloWorld.java^L^@^H^@ ^A^@^LHello World!^G^@^Y^L^@^Z^@^[^G^@^\^L^@^]^@^^^L^@^]^@^_^A^@
HelloWorld^A^@^Pjava/lang/Object^A^@^Pjava/lang/System^A^@^Cout^A^@^ULjava/io/PrintStream;^A
^@^Sjava/io/PrintStream^A^@^Gprintln^A^@^U(Ljava/lang/String;)V^A^@^D(I)V^@!^@^F^@^G^@^@^@^@^@^B^@^A^@^H^@  ^@^A^@

3. Descompilando o arquivo HelloWorld.class e vendo o código fonte original

Para esta demonstração utilizaremos o decompilador Jad que é gratuíto para um uso não comercial. Realize o download da respectiva versão para o seu sistema operacional. Use o jad para realizar a engenharia reversa do arquivo HelloWorld.class e recuperer o código fonte original, como mostrado a seguir:

$ unzip jadls158.zip
$ ./jad HelloWorld.class
Parsing HelloWorld.class…
Generating HelloWorld.jad
$ vi HelloWorld.jad <Isto irá mostrar o código fonte original, fruto da execução da engenharia reversa>

Ofuscando a sua aplicação java

Agora iremos ver como ofuscar e proteger o seu código fonte da engenharia reversa, usando o ProGuard que é um software gratuíto com licensa GPL.

1. Faça o Download e instale o ProGuard

$ cd /home/jsmith
$ unzip proguard4.2.zip

2. Crie um arquivo de configuração proguard

Crie um myconfig.pro que conterá as informações sobre a sua aplicação java.

-injar : Especifica a localização do seu arquivo jar, o qual contém os arquivos .class da compilação da sua classe java.

-outjar : Este é o arquivo jar que o proguard irá criar após a ofuscação do código. Este conterá todo o código alterado, lacrado, com as nomenclaturas de métodos e variáveis obscurar, o que vai dificultar muito para algum humano converseguir realizar a engenharia reversa.

-printmapping : ProGurad irá gerar uma saída com todas as saídas, em um arquivo com as informações mapeadas, em um arquivo que você especificar.

-keep : Incida os arquivos .class ou os métodos que você não quer que o ProGuard altere.

Para exemplificar, imagineos um mypkg.MainAppFrame como informação de onde está a nossa classe principal da aplicação, sendo esta classe neste exemplo, nós não queremos que seja ofuscada pelo ProGuard, como no exemplo a seguir:

$ cat myconfig.pro
-injars /home/jsmith/myapp.jar
-outjars /home/jsmith/myapp-obfuscated.jar This is the obfuscated jar file
-libraryjars /usr/java/jdk1.5.0_14/jre/lib/rt.jar
-printmapping proguard.map
-verbose
-keep public class mypkg.MainAppFrame

3. Execute o ProGuard

$ cd /home/jsmith/proguard4.2/lib
$ java -jar proguard.jar @myconfig.pro

Isto irá criar 2 arquivos, descritos a seguir:

* myapp-obfuscated.jar: Contém os arquivos das .class ofuscados da sua aplicação. E este você poderá distribuir sem medo algum de que alguem venha tentar realizar uma engenharia reversa, não que seja impossível, mas vai dar muito trabalho, o que acaba fazendo com que desistam da idéia.
* proguard.map: Este arquivo contém as informações do mapeamento para você se referenciar, sobre o que foi feito.

4. Exemplo de arquivo proguard.map

Este exemplo de arquivo proguard.map é o que indica o nome original que havia nos fontes java (nome do .class, métodos, variáveis, etc) e o respectivo nome a ser utilizado.

myapp.AppToolBar -> myapp.ae:
javax.swing.JButton btnNew -> d
javax.swing.JButton btnOpen -> e

5. Exemplo de código java (myapp.AppToolBar) antes de ser ofuscado

  1. btnNew = changeButtonLabel(btnNew, language.getText("new"));  
  2. btnOpen = changeButtonLabel(btnOpen, language.getText("open"));  
btnNew = changeButtonLabel(btnNew, language.getText("new"));
btnOpen = changeButtonLabel(btnOpen, language.getText("open"));

6. Exemplo de código fonte java que foi decompilado de um arquivo .class (myapp.ae) despois deste ter sido ofuscado

  1. d = a(d, n.a("new"));  
  2. e = a(e, n.a("open"));  
d = a(d, n.a("new"));
e = a(e, n.a("open"));

Aqui você pode ver a linha “btnNew = changeButtonLabel(btnNew, language.getText(”new”));” que foi traduzida para “d = a(d, n.a(”new”));”, pelo ProGuard, essa linha de código que não irá fazer sentido nenhum para alguem que venha a decompilar esta classe em uma engenharia reversa.

Postado por: evandropaes | Junho 16, 2008

Pivot: Uma nova forma de GUI para JAVA

Pivot é um framework open-source para desenvolvimento RIA que pode ser distribuido facilmente pela web ou offline(desktop).


Confira o demo aqui: https://pivot.dev.java.net/nonav/tutorials/demo.standalone.html e o blog do criador.

Postado por: evandropaes | Maio 30, 2008

Tutorial Facelets

Postado por:

Fonte: http://javawora.blogspot.com/search/label/JEE

Olá a todos, este é o primeiro tutorial que aborda o assunto de Facelets aqui no JavaWora. Acredito que todos que gostam de Java Server Faces estão super acostumados com a tecnologia, mas aqueles que usavam Struts e html puro, uma vez no mundo do JSF, uma das principais dificuldades (contornáveis é claro) era compreender a lógica das tags que de certa forma se distância do HTML convencional, o que eu até discordo em partes, afinal acho que um <html:text/> não se aproxima tanto de <input type=”text”/>, mas tudo bem, sabemos que da mesma forma aprender Struts não é uma tarefa das mais fáceis. Enfim vamos ao que interessa.

Um dos pontos que mais desagrada empresas que vão utilizar JSF é a distância do HTML convencional, portanto uma dificuldade de que designers possam efetuar atualizações, manutenções e coisas do gênero em uma página, pois bem, para “simplificar” toda essa dificuldade, foi desenvolvido uma tecnologia chamada de Facelets, aqueles que já viram o Tapestry verão muitas semelhanças, apontada como uma das inspiradoras para o Facelets.
No Tapestry utilizávamos a palavra chave jwcid (Java Web Component Id), para que o Framework substituísse aquele conteúdo por um componente desejado, e eis que apresento a palavra mágica do Facelets: jsfc (Java Server Faces Component). Não se engane isso não é uma cópia descarada, mas uma inspiração do primo de JSF, mas qual a mágica de tal palavrinha no caso de Facelets?O que ganhamos com isso?

Imagine o seguinte, você recebe a pagina HTML do designer, e você tem que alterar tudo aquilo, porque é tudo diferente do que você usa. Seus problemas acabaram! Basta você por uma palavrinha mágica em componentes, por exemplo:

<input type=”text”/>
Adicione:

<input type=”text” jsfc=”h:inputText” value=”#{cadastro.nome}”/>

Mágico, não acham? Um reaproveitamento de código maravilhoso e louvável. Outro ponto que nos interessa em reaproveitamento é a criação de um template, tiles é um bom framework mas deixa a desejar em alguns pontos. Com Facelets podemos definir um template declarativamente, de forma que a página sabe em qual template está inserida, reduzindo o esforço para descobrir seus componentes.
Para criar um template apenas devemos assinar os componentes da página por meio de <ui:insert name=”menu”> dentre as tags do facelets, caso queiramos inserir o conteúdo de um html naquele tag na página que define o template, utilizamos então: <ui:include src=”/templates/menu.xhtml”/>. No momento em que vamos utilizar um determinado template numa página, basta declará-lo: <ui:composition template=”/templates/common.xhtml”>, e inserir o que estmos sobrescrevendo por meio de <ui:define name=”body”>conteúdo</ui:define> no espaço delimitado pelas tags em conteúdo. Mais uma vez, simples, muito simples. O Facelets ainda possui componentização, Ájax integrado, dentre outras funcionalidades, mas vamos nos focar no core aqui, que é templates e reaproveitamento de html original.
O suporte de IDES ao Facelets ainda é fraco, o NetBeans possui um suporte, já no universo eclipse, temos o Exadel e agora o novíssimo Red Hat Developer Studio, os melhores na minha opinião. O exemplo deste tutorial foi desenvolvido com a implementação da Sun e no tomcat 5.5, no tomcat 6 algumas mudanças são necessárias. Os jars necessários são:

  • common-annotations.jar
  • commons-beanutils.jar
  • commons-collections.jar
  • commons-digester.jar
  • commons-logging.jar
  • el-api.jar
  • el-ri.jar
  • jsf-api.jar
  • jsf-facelets.jar
  • jsf-impl.jar
  • jsf-tlds.jar
  • jstl.jar
  • standard.jar


O web-xml necessário está na Figura 1. Criaremos três Classes para nossa lógica, são elas:

Listagem 1 – Login.java
package br.com.facelets.bean;
public class Login {
private String userName;
private String senha;
public Login() {
}
//sets e gets omitidos
@Override
public int hashCode() {
final int PRIME = 31;
int result = 1;
result = PRIME * result + ((senha == null) ? 0 : senha.hashCode());
result = PRIME * result + ((userName == null) ? 0 : userName.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
final Login other = (Login) obj;
if (senha == null) {
if (other.senha != null)
return false;
} else if (!senha.equals(other.senha))
return false;
if (userName == null) {
if (other.userName != null)
return false;
} else if (!userName.equals(other.userName))
return false;
return true;
}
}

Listagem 2 – Cadastro.java

package br.com.facelets.bean;
import javax.faces.context.FacesContext;
import br.com.facelets.business.CadastroSaver;
public class Cadastro {
private String nome;
private String senha;
private String userName;
public String getLogin() {
return userName;
}
public void setLogin(String login) {
this.userName = login;
}
//sets e gets omitidos
public String salvar(){
Login login = new Login();
login.setUserName(userName);
login.setSenha(senha);
CadastroSaver.salvar(login, this);
return “ok”;
}
public String logar(){
Login login = new Login();
login.setUserName(userName);
login.setSenha(senha);
Cadastro cadastro = CadastroSaver.busca(login);
if(cadastro!=null){
FacesContext.getCurrentInstance().getExternalContext().getSessionMap().put(”user”, cadastro);
return “ok”;
}else{
FacesContext.getCurrentInstance().getExternalContext().getRequestMap().put(”erro”, “login/senha inválidos”);
return “erro”;
}
}
}

Listagem 3 – CadastroSaver.java

package br.com.facelets.business;
import java.util.Hashtable;
import br.com.facelets.bean.Cadastro;
import br.com.facelets.bean.Login;
public class CadastroSaver {
private static final Hashtable saver = new Hashtable();
public static void salvar(Login login,Cadastro cadastro){
saver.put(login, cadastro);
}
public static Cadastro busca(Login login){
return saver.get(login);
}
}

E agora o faces-config e as páginas propriamente ditas.

Listagem 4- faces-config.xml

<?xml version=”1.0″ encoding=”UTF-8″?>
<faces-config version=”1.2″ xmlns=”http://java.sun.com/xml/ns/javaee”
xmlns:xi=”http://www.w3.org/2001/XInclude”
xmlns:xsi=”http://www.w3.org/2001/XMLSchema-instance” xsi:schemaLocation=”http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-facesconfig_1_2.xsd”>
<managed-bean>
<managed-bean-name>cadastro</managed-bean-name>
<managed-bean-class>br.com.facelets.bean.Cadastro</managed-bean-class>
<managed-bean-scope>request</managed-bean-scope>
<managed-property>
<property-name>nome</property-name>
<property-class>java.lang.String</property-class>
<value/>
</managed-property>
<managed-property>
<property-name>login</property-name>
<property-class>java.lang.String</property-class>
<value/>
</managed-property>
</managed-bean>
<navigation-rule>
<from-view-id>/pages/dados.xhtml</from-view-id>
<navigation-case>
<from-outcome>ok</from-outcome>
<to-view-id>/pages/inputname.xhtml</to-view-id>
<redirect/>
</navigation-case>
</navigation-rule>
<navigation-rule>
<from-view-id>/pages/login.xhtml</from-view-id>
<navigation-case>
<from-outcome>ok</from-outcome>
<to-view-id>/pages/greeting.xhtml</to-view-id>
<redirect/>
</navigation-case>
<navigation-case>
<from-outcome>erro</from-outcome>
<to-view-id>/pages/login.xhtml</to-view-id>
</navigation-case>
</navigation-rule>
<application>
<view-handler>com.sun.facelets.FaceletViewHandler</view-handler>
<resource-bundle>
<base-name>resources</base-name>
<var>msg</var>
</resource-bundle>
<message-bundle>resources</message-bundle>
</application>
</faces-config>

Listagem 5 – menu.xhtml

<!DOCTYPE html PUBLIC “-//W3C//DTD XHTML 1.0 Transitional//EN”
“http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd”>
<html xmlns=”http://www.w3.org/1999/xhtml”
xmlns:ui=”http://java.sun.com/jsf/facelets”
xmlns:h=”http://java.sun.com/jsf/html”
xmlns:f=”http://java.sun.com/jsf/core”>
<body bgcolor=”#ffffff”>
<table style=”border:1px solid #CAD6E0″ align=”center” cellpadding=”0″ cellspacing=”0″ border=”0″>
<tbody>
<tr>
<td colspan=”2″ valign=”bottom” height=”1″ bgcolor=”#CAD6E0″>
<table>
<tr>
<td>
<a href=”dados.jsf”>Incluir dados</a>
</td>
</tr>
<tr>
<td>
<a href=”login.jsf”>Login</a>
</td>
</tr>
</table>
</td>
</tr>
</tbody>
</table>
</body>
</html>

Listagem 6 – common.xhtml

<!DOCTYPE html PUBLIC “-//W3C//DTD XHTML 1.0 Transitional//EN” “http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd”>
<html xmlns=”http://www.w3.org/1999/xhtml”
xmlns:ui=”http://java.sun.com/jsf/facelets”
xmlns:h=”http://java.sun.com/jsf/html”
xmlns:f=”http://java.sun.com/jsf/core”>
<span jsfc=”f:loadBundle” basename=”resources” var=”msg”/>
<head>
<title>
<ui:insert name=”pageTitle”>JavaWora</ui:insert>
</title>
<style type=”text/css”>
body {
font-family: Verdana, Arial, Helvetica, sans-serif;
font-size: 14px;
}
.header {
font-family: Verdana, Arial, Helvetica, sans-serif;
font-size: 18px;
}
.bottom {
font-family: Verdana, Arial, Helvetica, sans-serif;
font-size: 9px;
text-align: center;
vertical-align: middle;
color: #8E969D;
}
</style>
</head>
<body bgcolor=”#ffffff”>
<table style=”border:1px solid #CAD6E0″ align=”center” cellpadding=”0″ cellspacing=”0″ border=”0″ width=”400″>
<tbody>
<tr>
<td class=”header” align=”center” valign=”middle” width=”100%” bgcolor=”#E4EBEB”>
<ui:insert name=”pageHeader”>JavaWora Facelets</ui:insert>
</td>
</tr>
<tr>
<td height=”1″ width=”100%” bgcolor=”#CAD6E0″></td>
</tr>
<tr>
<td width=”100%”>
<table width=”100%” style=”height:150px” align=”left” cellpadding=”0″
cellspacing=”0″ border=”0″>
<tbody>
<tr>
<td align=”center” width=”10%” valign=”middle”>
<ui:insert name=”menu”>
<ui:include src=”/templates/menu.xhtml”/>
</ui:insert>
</td>
<td align=”center” width=”75%” valign=”middle”>
<ui:insert name=”body”>Page Body</ui:insert>
</td>
</tr>
</tbody>
</table>
</td>
</tr>
<tr>
<td colspan=”2″ valign=”bottom” height=”1″ width=”100%” bgcolor=”#CAD6E0″></td>
</tr>
</tbody>
</table>
</body>
</html>

Listagem 7 – cadastro.xhtml

<!DOCTYPE html PUBLIC “-//W3C//DTD XHTML 1.0 Transitional//EN” “http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd”>
<ui:composition xmlns=”http://www.w3.org/1999/xhtml”
xmlns:ui=”http://java.sun.com/jsf/facelets”
xmlns:h=”http://java.sun.com/jsf/html”
xmlns:f=”http://java.sun.com/jsf/core”
template=”/templates/common.xhtml”>
<head>
<meta http-equiv=”Content-Type” content=”text/html; charset=ISO-8859-1″ />
<title>Cadastro</title>
</head>
<ui:define name=”body”>
<form jsfc=”h:form” id=”cadastro”>
<table>
<tr>
<td>Nome*:</td>
<td>
<input type=”text” jsfc=”h:inputText” value=”#{cadastro.nome}” id=”nome” label=”#{msg.lbl.nome}” required=”true” requiredMessage=”#{msg.erroRequired}”/>
</td>
<td><h:message for=”nome” id=”erroNome”></h:message> </td>
</tr>
<tr>
<td>login*:</td>
<td>
<input type=”text” jsfc=”h:inputText” value=”#{cadastro.login}” id=”login” label=”#{msg.lbl.login}” required=”true” requiredMessage=”#{msg.erroRequired}”/>
</td>
<td><h:message for=”login” id=”erroLogin”></h:message> </td>
</tr>
<tr>
<td>senha*:</td>
<td>
<input type=”text” jsfc=”h:inputSecret” value=”#{cadastro.senha}” id=”senha” label=”${msg.lbl.senha}” required=”true” requiredMessage=”#{msg.erroRequired}”/>
</td>
<td><h:message for=”senha” id=”erroSenha”></h:message> </td>
</tr>
<tr>
<td>Estado Civil:</td>
<td>
<select jsfc=”h:selectOneMenu” value=”#{cadastro.idEstado}” id=”eCivil” label=”#{msg.lbl.estadoCivil}”>
<option jsfc=”f:selectItem” itemValue=”1″ itemLabel=”Casado”></option>
<option jsfc=”f:selectItem” itemValue=”2″ itemLabel=”Solteiro”></option>
<option jsfc=”f:selectItem” itemValue=”3″ itemLabel=”Divorciado”></option>
</select>
</td>
</tr>
<tr>
<td colspan=”2″ align=”center”>
<input type=”submit” value=”Salvar” jsfc=”h:commandButton” action=”#{cadastro.salvar}”/>
</td>
</tr>
</table>
</form>
</ui:define>
</ui:composition>

Listagem 8 – inputname.xhtml

<!DOCTYPE html PUBLIC “-//W3C//DTD XHTML 1.0 Transitional//EN”
“http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd”>
<html xmlns=”http://www.w3.org/1999/xhtml”
xmlns:ui=”http://java.sun.com/jsf/facelets”
xmlns:h=”http://java.sun.com/jsf/html”
xmlns:f=”http://java.sun.com/jsf/core”
xmlns:c=”http://java.sun.com/jstl/core”>
<ui:composition template=”/templates/common.xhtml”>
<ui:define name=”pageTitle”>
Bem Vindo
</ui:define>
<ui:define name=”pageHeader”>
Home
</ui:define>
<ui:define name=”body”>
${msg.prompt}
</ui:define>
</ui:composition>
</html>

Listagem 9 – greeting.xhtml

<!DOCTYPE html PUBLIC “-//W3C//DTD XHTML 1.0 Transitional//EN” “http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd”>
<html xmlns=”http://www.w3.org/1999/xhtml”
xmlns:ui=”http://java.sun.com/jsf/facelets”
xmlns:h=”http://java.sun.com/jsf/html”
xmlns:f=”http://java.sun.com/jsf/core”>
<f:loadBundle basename=”resources” var=”msg” />
<ui:composition template=”/templates/common.xhtml”>
<ui:define name=”body”>
#{msg.greeting} <span jsfc=”h:outputLabel” value=”#{sessionScope.user.nome}”/>!
</ui:define>
</ui:composition>
</html>

Listagem 10 – login.xhtml

<!DOCTYPE html PUBLIC “-//W3C//DTD XHTML 1.0 Transitional//EN” “http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd”>
<ui:composition xmlns=”http://www.w3.org/1999/xhtml”
xmlns:ui=”http://java.sun.com/jsf/facelets”
xmlns:h=”http://java.sun.com/jsf/html”
xmlns:f=”http://java.sun.com/jsf/core”
template=”/templates/common.xhtml”>
<ui:define name=”body”>
#{erro}
<form jsfc=”h:form” id=”login”>
<table>
<tr>
<td>Login:</td><td><input jsfc=”h:inputText” value=”#{cadastro.login}” type=”text”/></td>
</tr>
<tr>
<td>Senha:</td><td><input jsfc=”h:inputSecret” value=”#{cadastro.senha}” type=”password”/></td>
</tr>
<tr>
<td colspan=”2″ align=”center”>
<input jsfc=”h:commandButton” action=”#{cadastro.logar}” type=”submit” value=”OK”/>
</td>
</tr>
</table>
</form>
</ui:define>
</ui:composition>

Experimente abrir a pagina de login no firefox, ie, ou qualquer ferramenta WYSIWYG (acho q é isso) e veja que os parametros estão lá, até a pagina, mas como isso é possível? Ora como eu disse trata-se de uma página simples xhml, a propósito podemos trabalhar com xhtml diretamente em facelets, ou mesmo jsps, mas xhtml é mais legal. A aplicação consiste em efetuar um cadastro e logo após um login para verificar se os dados foram armazenados.
Agora vamos as curiosidades. Conforme observado no web.xml, há dois listeners registrados, eles são necessários para o Tomcat 5.5, pois o compilador utilizado no facelets não é o Jasper que vêm nele, mas um próprio.
No web.xml observe a sentença:

<context-param>
<param-name>facelets.DEVELOPMENT</param-name>
<param-value>true</param-value>
</context-param>

Cause um erro em uma página e observe o que ocorre, figura 2:

O compilador descreve o erro e lhe auxilia com a arvores de componentes gerada e os dados do que estavam presentes. Legal né! Pois agora troque a sentença para false. Você verá que o erro agora é apresentado como na figura 3. Bonito não?!

Obrigado e até mais!

Postado por: evandropaes | Maio 16, 2008

Alterando a sequencia de boot do ubuntu

Digite no terminal:

sudo gedit /boot/grub/menu.lst

O linux solicitará a senha de usuário.

Com o arquivo aberto, procure a linha que que contém default X. O X significa o sistema operacional padrão para o boot. Conte o número do title que representa o windows, lembrando que é iniciado por 0 (zero), e altere o arquivo depois é só salvar.

Evandro

Postado por: evandropaes | Maio 8, 2008

DEZAINE GRÁPHICO-TABELA DE PREÇOS

Fonte: http://www.ifd.com.br/blog/2005/09/23/dezaine-grphico-tabela-de-preos/

Conheça esta tabela bem humorada com dicas para cobrar aquele “cliente especial”.

Serviço Valor (R$)
[1] Logo marca, logomarca 6000,00
Logotipozinho, logomarcazinha, marquinha e marquinhazinha (preço também válido para logotipo bem pequenininho, simbolo, desenho pra colocar no cartão e elipse e degrade) 2250,00
Nome do logotipo 5500,00
Impresso 855,00
Folheto de divulgação 255,00
Convitezinho 345,00
Panfleto 452,00
Um folder rapidinho 1250,00
Prospecto 355,00
Jeitinho aqui 150,00
Folhinha / Filipeta 355,00
Folhinha pra tirar xérox mesmo (xérox não inclusas) 456,00
Uma faixa aí 2230,00
Cartaz “que você ja pega pronto no Print artist” 564,00
“Botar um design” no meu site 5300,00
Desenho animado pra colocar no site 50000,00
Uma letra girando, assim ó 250,00
Cartãozinho mixuruca 150,00
Só pra não passar em branco (Folder de aniversário de 50 anos da empresa) 6000,00
Um site (Não interessa a quantidade de paginas, nem o que tem dentro, site é site, ué) 15000,00
Um portal (Sem diferença para o material acima, apenas na nomenclatura) 30000,00
“Igualzinho a esse aqui, só vai colocar o meu timbre ao inves do dele aqui em cima, entendeu? Pra não dar trabalho mesmo…” 1000,00
Sem muitos detalhes 350,00
Quando começar a frase com:
Acrescentar mais (R$)
“Isso aí, você coloca no computador e ele faz” 1250,00
“Eu tenho um sobrinho que faz assim…” 350,00
“Ei, você que mexe com computador…” 500,00
“Ah foi bom te ver aqui, você não é o cara da informáica?” 8000,00
“O chefe do departamento ja escolheu até a letra e a cor, agora ficou fácil” 250,00
“Não, não.. você nao vai ter trabalho nenhum, mesmo. É so colocar no computador mesmo” 350,00
“Na verdade o serviço JÁ ESTÁ PRONTO! É só colocar um pouco de design” 750,00
“É só uma firula mesmo né?” 450,00
“Pra enfeitar o pavão…” 360,00
“Na verdade é porque eu não tenho tempo pra fazer..” 2500,00
“Eu confio em você, vê ai alguma coisa..” (não sabe nem o nome da empresa) 5500,00
“Depois a gente vê uma maneira de te compensar…” 240.000,00
“Vê ai o que você faz pra mim?” 890,00
“Nossa, mas é so um site! Isso tudo?” 5000,00
“POR PÁGINA??????” (cada vez que a pessoa repetir essa frase) 345,00
“Aproveita pra ver o que aconteceu com o antivirus daqui da loja?” 350,00
“Ah.. tá.. mas nisso ja estão incluidas as fotos e as modelos né?” 150,00
“É só esticar aqui, ó” 60,00
“E você usa o computador pra isso?” 75,00
“Coisa simples” 2500,00
“Não você não entendeu é simples mesmo” 3500,00
“É você não entendeu mesmo” 4500,00
“Só uma galeria de fotos. Quantas fotos? Ah umas 100, mas é so colocar ali no canto” 890,00
“Ué, mas é so digitar como ta aqui no jornal.” 980,00
“Escaneia daqui da revista mesmo” 200,00
“Eu quero um site” (Mecãnico free-lancer) 2800,00
“DUZENTOS E CINQUENTA REAIS???” (subir mais R$ 50,00 a cada grito de desespero) 50,00
“Fotolito? Não, não, não vamos contratar fotografo” 35,00
“Ah!! Pode pegar o logo do nosso site, não tem problema nenhum, eu autorizo. É so clicar com o botão direito do mouse em cima e ir em ’salvar como’…” 890,00
“COMO ASSIM, SEM A IMPRESSÃO???” (afinal o cara ainda vai pagar a impressão!!) 200,00
“E quanto você cobra assim? Pra um site, é. Completo! Sim eu sei, mas mais ou menos? Tira uma média, site completo! Hum.. e outro mais simplezinho?” 450,00
“Ah mas eu achei a mesma coisa por R$ 30,00 cada página. E é serviço de confiança. O que a gente pode fazer pra chegar nisso?” (esses eu tenho vontade de xingar…) 200,00
“Pois é mas eu estou vendo com outras pessoas…” 100,00
“Ta, tudo bem.. e fica pronto quando? Pode me mandar uma previa por email hoje a noite? 5000,00
(numa sexta feiras 17:55) “ok, me entrega na segunda até umas 10h tá bom?” 8000,00
“É que meu prazo já está estourado, sabe como é né?” 4580,00
Serviços extras – depois do trabalho pronto:
“Aumenta essa letra?” 50,00
“Coloca esse amarelo mais vivo?” 90,00
“Troca esse vermelho, por amarelo?” Sob consulta. Em casos como trocar o tom da pele de uma foto fica mais caro.
“Vira o rosto dela no computador, pra ficar de lado, acho q vai ficar melhor” (foto 3×4) 150,00 (e não realiza o serviço, lógico)
“E se a gente mudasse o menu pra cá? To achando isso meio parado…” (site pronto) Valor do site x 5
(Depois de pedir incessantemente pelo estetoscopio na capa do manual médico) “É mesmo, né? Não ficou muito legal….. e agora?” 6000,00
“Puxa mais pra ca.. Isso agora mais pra ca, isso, troca essa cor.. agora inclui essa foto… podia mudar aqui ne? hum… po parace que piorou não estou entendendo…” 8500,00

Agora falando sério, o IFDBlog tem o post [2] QUANTO COBRAR? com diversas tabelas referenciais de preços das melhores associações de profissionais da área de comunicação do Brasil e do Mundo além de dicas que podem ajudar você a formular o preço do seu trabalho, vale a pena dar um olhada.


Matéria impressa através do IFDBlog: http://www.ifd.com.br/blog

URL da matéria: http://www.ifd.com.br/blog/2005/09/23/dezaine-grphico-tabela-de-preos/

URLs in this post:
[1] Logo marca, logomarca: http://www.ifd.com.br/blog/2005/11/22/logomarca/
[2] QUANTO COBRAR?: http://www.ifd.com.br/blog/2004/07/29/quanto_cobrar/

Postado por: evandropaes | Abril 25, 2008

Criar um pool de conexões no Apache Tomcat

Fonte: http://www.antoniopassos.pro.br/blog/?p=88

1)Configurando o pool de conexões…

No diretório META-INF da aplicação, crie um arquivo “context.xml” com o seguinte conteúdo…

<?xml version=”1.0″ encoding=”UTF-8″?>
<Context auth=”Container”>
<Resource
name=”jdbc/bd_teste”
type=”javax.sql.DataSource”
url=”jdbc:mckoi://localhost:59999/”
driverClassName=”com.mckoi.JDBCDriver”
username=”admin”
password=”123456″
maxActive=”100″
maxIdle=”20″/>
</Context>

Significado de cada atributo usado no arquivo “context.xml“…

  • auth –> Atribui ao Apache Tomcat a responsabilidade de gerenciar a abertura e o fechamento das conexões
  • name –> Nome dado ao pool de conexões. Deve obedecer o formato JNDIATENÇÃO: O NOME DADO AO POOL DEVERÁ SER O MESMO USADO NO ARQUIVO WEB.XML DA APLICAÇÃO.
  • type –> Especifica o tipo como sendo DataSource
  • url –> Especifica a localização do banco de dados. Deve obedecer o formato URL JDBC
  • driverClassName –> Nome da classe do driver JDBC do banco de dados
  • username –> Nome do usuário do BD
  • password –> Senha do usuário do BD
  • maxActive –> Número máximo de conexões ativas no pool
  • maxIdle –> Número máximo de conexões inativas no pool
  • maxWait –> Tempo máximo de espera por uma conexão, em milissegundos

2)Registrando o pool no aplicativo…

No arquivo “web.xml” da aplicação, insira as linhas abaixo…

<resource-ref>
<res-ref-name>
jdbc/bd_teste
</res-ref-name>
<res-type>
javax.sql.DataSource
</res-type>
<res-auth>
Container
</res-auth>
</resource-ref>

ATENÇÃO: O valor em “<res-ref-name>” deve corresponder ao nome dado ao pool de conexões no arquivo “context.xml”. No caso a “jdbc/bd_teste”.

3)Testando o pool..

3.1) Crie uma classe “ServiceLocator.java” com o seguinte conteúdo…

import java.sql.Connection;
import javax.naming.InitialContext;
import javax.sql.DataSource;

public class ServiceLocator {

public static Connection getConexao(String JNDINome) throws Exception {
Connection con = null;

// Obtém a raiz da hierarquia de nomes
InitialContext contexto = new InitialContext();

// Obtém a origem dos dados
DataSource ds = (DataSource)contexto.lookup(”java:comp/env/” + JNDINome);

// Obtém uma conexão
con = ds.getConnection();

// Retorna a conexão
return con;
}
}

3.2) Crie um servlet, que use a classe ServiceLocator acima para obter uma conexão do pool…

import java.io.IOException;
import java.io.PrintWriter;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public class ServletExemplo extends javax.servlet.http.HttpServlet implements javax.servlet.Servlet {

private static final String JNDINome = “jdbc/bd_teste”;

public ServletExemplo() {
super();
}

protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
response.setContentType(”text/html”);
PrintWriter out = response.getWriter();
out.println(”<h1>Filmes cadastrados</h1>”);

Connection con = null;
try {
con = ServiceLocator.getConexao(JNDINome);
} catch (Exception e) {
e.printStackTrace();
}

String sql = “SELECT * FROM filmes”;
PreparedStatement stmt;
try {
stmt = con.prepareStatement(sql);
ResultSet rs = stmt.executeQuery();
while (rs.next()){
out.println(”Código -> ” + rs.getInt(1) + ” Título -> ” + rs.getString(2));
}
} catch (SQLException e) {
e.printStackTrace();
}
}

protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doGet(request, response);
}
}

<!–
google_ad_client = “pub-9909948656853681″;
google_ad_output = “textlink”;
google_ad_format = “ref_text”;
google_cpa_choice = “CAAQmbj2_gEaCNYZLJsrWhfIKL264YcBMAA”;
google_ad_channel = “9871635485″;
//–>

Postado por: evandropaes | Abril 25, 2008

Gerador de senha em PHP

Fonte: http://mrsantos76.wordpress.com/

Pessoal esse script originalmente não foi eu que escrevi, vi ele uma vez na web, sinceramente não lembro onde
apenas modifiquei ele pra atender minhas necessidades e acertei um detalhe que tinha no ultimo if…
segue o cara…


///////////////////////////////////////
//
// Gerador de senha:
// uso: gerador_senha("L N L N L N")
// sendo que cada  L é uma letra
// e cada N é um numero
// nessa caso teriamos algo como k3j4j5
//
///////////////////////////////////////
function gerador_senha($tipo="L L N N")
{
    $tipo = explode(' ', $tipo);
    $padrao_letras = 'a|b|c|d|e|f|g|h|i|j|k|l|m|n|o|p|q|r|s|t|u|v|x|w|y|z';
    $padrao_numeros = '0|1|2|3|4|5|6|7|8|9';
    $array_letras = explode('|', $padrao_letras);
    $array_numeros = explode('|', $padrao_numeros);
    $senha = "";
    for ($i=0; $i < count($tipo); $i++)
   {
        if ($tipo[$i] == ‘L’)
       {
             $senha .= $array_letras[array_rand($array_letras,1)];
        }
        else
       {
           $senha .= $array_numeros[array_rand($array_numeros,1)];
       }
    }
     return $senha;
}
Postado por: evandropaes | Abril 3, 2008

Entendendo o serialVersionUID

Por Paulo Silveira em 01/04/2008 -

Fonte: http://blog.caelum.com.br/2008/04/01/entendendo-o-serialversionuid/

O serialVersionUID é uma dúvida constante entre muitos desenvolvedores. Afinal, quando e para que exatamente usá-lo? Devo gerar um número aleatório bem grande, ou um número qualquer? Essas perguntas são comuns, e ao desenvolvedor experiente é necessário conhecer a fundo esse detalhe do processo de serialização do Java.

Quando um objeto é serializado no Java, essa sequência de bytes, além de conter seus atributos de instância não transientes, carrega consigo um número que indentifica a “versão” da classe que foi usada durante o processo. Esse é o chamado serialVersionUID, ou seja, o indentificador de versão de serialização de uma classe. Esse número é utilizado para saber se o objeto que estamos recuperando é de uma versão “compatível” com a versão da classe que foi utilizada quando serializamos o objeto: em outras palavras, os arquivos .class não precisam ser necessariamente os mesmos para que o processo de serialização ocorra com sucesso.

Por exemplo, considere a seguinte classe Usuario:

package br.com.caelum;

public class Usuario implements Serializable {
  private String login;
}

Essa classe possui o serialVersionUID igual a 2806421523585360625L. Esse número não é aleatório! Ele é um hash (SHA) calculado em cima dos nomes dos seus atributos, e assinaturas dos métodos em uma ordem bem definida pela especificação do processo de serialização. E como eu sei esse número? O JDK vem com a ferramenta serialver, que implementa esse mesmo hash:

serialver br.com.caelum.Usuario

Se o serialVersionUID utilizado durante a serialização não bater exatamente com o serialVersionUID da classe que está sendo usada para recuperar essa informação, uma exception é lançada: java.io.InvalidClassException.

Por exemplo, se adicionarmos um novo atributo na nossa classe Usuario:

public class Usuario implements Serializable {
  private String login;
  private String senha;
}

Agora teremos o serialVersionUID valendo 416295346730660862L. Caso você serialize um Usuario com a primeira classe aqui definida, e tentar recuperar essa informação usando essa nova versão de classe, receberemos a conhecida java.io.InvalidClassException. Esse é o comportamente que em muitos casos queremos, mas algumas vezes fazemos pequenas modificações na classe as quais percebemos que não impactarão no processo de serialização, e precisamos manter compatibilidade com a versão antiga daquela classe. Para isso, basta definirmos explicitamente qual é o nosso serialVersionUID, e no caso de querer manter compatibilidade com a classe Usuario anterior, vamos utilizar o valor de serialVersionUID que seria gerado pela JVM: 2806421523585360625L. O código ficaria:

public class Usuario implements Serializable {
  private static final long serialVersionUID = 2806421523585360625L;
  private String login;
  private String senha;
}

Às vezes recebemos um warning do Eclipse, e ele pede para que seja definido o serialVersionUID da classe em questão. Isso ocorre porque você implementa Serializable ou uma de suas mães a implementa. O Eclipse então te abre três opções: utilizar o @SurpressWarnings para você assumir o risco, usar um valor default, ou usar o valor gerado. O gerador de UIDs do Eclipse é exatamente o mesmo gerador utilizado pelo Java SE para criar os UIDs padrão! Reforçando, esse número não é um número aleatório!

serialVersionUIDQuando alguém esquece de manter o mesmo serialVersionUID para duas versões compatíveis de uma classe, podemos ter problemas em usar diferentes versões do software que são teoricamente compatíveis. Isso muitas vezes acontece em servidores de aplicação, e se seu cliente esta desatualizado em relação a versão dos jars necessários pelo servidor, podemos ter alguns InvalidClassExceptions que poderiam ser facilmente evitados se o serialVersionUID tivesse sido corretamente aplicado. Claro que algumas outras vezes as versões realmente não são compatíveis e a exception procede.

Esse grave problema pode acontecer mesmo usando classes do Java SE entre diferentes versões, como é o caso da classe java.text.AttributedCharacterIterator.Attribute (utilizada pela java.awt.Font). Do Java 1.3 para o Java 1.4 essa classe foi levemente alterada, e o serialVersionUID gerado pelo algoritmo da JVM desta classe mudou de -1514471214376796190L para -9142742483513960612L. Quando alguém serializava uma java.awt.Font em uma versão não podia desserializa-la em outra, sendo que as versões tecnicamente são compatíveis: a não definição explícita do serialVersionUID gerou um bug no Java SE. Como isto foi resolvido? Definiram o serialVersionUID como -1514471214376796190L, que é o valor que seria gerado pela JVM na versão anterior da classe.

Como então devemos proceder para escolher um serialVersionUID apropriado? É muito simples: se essa classe está nascendo neste momento, você pode se dar ao luxo de utilizar um serialVersionUID, como por exemplo:

public class Usuario implements Serializable {
  private static final serialVersionUID = 1L;
  private String login;
}

Porém se você está definindo o serialVersionUID de uma classe já em produção, e sabe que a mudança que está fazendo é compatível com a versão anterior, você deve utilizar o serialVersionUID que seria gerado pela JVM na primeira versão, como foi o caso aqui quando adicionamos o atributo senha na classe Usuario, e também foi o caso da correção do bug da classe java.text.AttributedCharacterIterator.Attribute. Quando você fizer uma alteração onde percebe que o cliente precisará de atualização das classes envolvidas, basta definir um serialVersionUID diferente dos anteriormente utilizados.

Para completar, implementar uma interface que não define métodos (Serializable) e ser forçado a escrever um atributo sem um contrato mais burocrático é um tanto estranho em uma linguagem como o Java. Sem dúvida, se esse mecanismo todo tivesse sido inventado já com a existência de anotações, Serializable seria uma anotação e version um atributo dela, talvez obrigatório, criando algo como @Serializable(version=12345L). Boas serializações e invocações remotas!

Postagens Antigas »

Categorias