quarta-feira, 2 de setembro de 2009

JPA e "last_insert_id"

Você já passou pelo problema de inserir um registro em uma tabela e logo a seguir precisar desse código pra relacionar com outra tabela (por exemplo....) e o seu objeto de persistência não retornar esse código?

Então seus problemas acabaram.... na classe da sua entidade, mais precisamente no campo que identifica a chave primária (autoincrement) da tabela, basta você inserir:

@GeneratedValue(strategy=GenerationType.IDENTITY)

Por exemplo:

@Id
@GeneratedValue(strategy=GenerationType.IDENTITY)
@Column(name = "codigo", nullable = false)
private Integer codigo;

Depois disso, após a chamada do commit você poderá chamar o método que retorna o código criado para o objeto, essa dica por retirada do endereço:

http://en.wikibooks.org/wiki/Java_Persistence/Identity_and_Sequencing#Identity_sequencing


T+

terça-feira, 11 de agosto de 2009

Icone para uma aplicação J2ME

Opa... to vivo ainda... :-)

Terminei um sistema de venda/ cancelamento de venda via celular utilizando um plano de dados da operadora de celular, e achei que o software merecia um ícone pra quando o usuário fosse acessá-lo, os passos pra fazer isso é o seguinte:

1) Abra o seu projeto no Netbeans (meio óbvio...)
2) Deixe a aba "Projetos" aberta
3) Arraste a imagem para dentro do PACOTE do seu projeto, pra facilitar jogue pra dentro do mesmo pacote dos códigos fonte, o tamanho deve ser 12x12 , 15x15, vai depender do tipo de celular... e tem que ser PNG (na verdade não testei com outros formatos)
4) Clique com o botão direito sobre o projeto e selecione a opção PROPRIEDADES
5) Selecione a categoria "Descritor de aplicativos"
6) Clique no botão "Adicionar"
7) Preencha as propriedades:
Nome: MIDlet-Icon
Valor: /[nome_do_pacote]/[nome_da_imagem]

É isso aí...

Se alguém precisar e não conseguiu compreender me avisa que eu coloco as imagens.

[]'s

quarta-feira, 25 de março de 2009

Código java compilado?

Sempre pensei na facilidade de decompilação de um arquivo jar criado em java, buscando uma solução pra isso acabei encontrado o gcj que compila um código java criando um executável sem chance de ser decompilado (ou pelo menos muuuuuuito mais difícil do que o jar), veja um exemplo:

HelloWorld.java:

public class HelloWorld {
public static void main(String [] args) {
System.out.println("Teste com java compilado para codigo nativo$
}
}


Basta compilar assim (claro que o gcj tem que estar previamente instalado):
gcj --main=HelloWorld -o HelloWorld HelloWorld.java


Com isso será criado o arquivo HelloWorld com permissão de execução (no caso do Linux) e para executá-lo:
./HelloWorld

Seria interessante poder utilizar diretamente no NetBeans, pois geralmente um projeto em java não se limita a uma única classe e penso eu que se estiver dentro do NetBeans ele mesmo vai criar as condições necessárias para utilizar o gcj sem muito esforço, então encontrei a página http://wiki.netbeans.org/FaqGcj mas ainda não deu tempo de testar pra ver se realmente funciona.

T+

sexta-feira, 6 de março de 2009

Broken pipe: A SOLUÇÃO CORRETA

Não vou negar... quebrei muito a cabeça com esse problema em um sistema que recebe conexões via socket, o problema se dava quando ficava muito tempo se receber conexões, eis que acabava gerando o erro "Broken pipe"... e nada mais funcionava, a minha primeira tentativa (com sucesso) mas não muito elegante, pois poderia acarretar em outros problemas está no post:
http://netbeando.blogspot.com/2008/06/broken-pipe-conexo-com-socket-no-banco.html

Bom, agora apresento a solução mais elegante...

1) Para criar um pool de conexões com o banco, inclua no seu projeto a biblioteca c3p0 e faça a conexão dessa forma:

ComboPooledDataSource cpds = new ComboPooledDataSource();
cpds.setDriverClass("com.mysql.jdbc.Driver");
cpds.setJdbcUrl("jdbc:mysql://localhost:3306/nome_base_dados");
cpds.setUser("usuario_banco");
cpds.setPassword("senha_usuario_banco");
cpds.setMinPoolSize(5);
cpds.setAcquireIncrement(5);
cpds.setMaxPoolSize(20);
cpds.setIdleConnectionTestPeriod(60);
cpds.setMaxStatements(0);
cpds.setInitialPoolSize(3);
cpds.setPreferredTestQuery("select 1");
cpds.setCheckoutTimeout(1000);

con = cpds.getConnection();

Essas foram as configurações que eu utilizei para testes no meu tipo de sistema, pesquise sobre o c3p0 e veja quais serão as que se adaptam melhor ao seu problema.

2) Por último, mas não menos importante, sete a propriedade do socket (server) que recebe as conexões do cliente:

private static Socket conexao;
.
.
.
public static void main(String[] args) {
.
.
.
conexao.setKeepAlive(true);
.
.
.
}


Fazendo esses 2 itens resolveu completamente o problema.

Espero que ajude a você também...

quinta-feira, 5 de junho de 2008

Broken pipe na conexão com socket no banco de dados

Bom, pra não perder o histórico do blog (já que realmente não costumo postar muito) vou deixar a solução digamos meio que "gambearristica" encontrada abaixo, mas que me resolveu o problema no momento e vou criar outro tópico sobre esse mesmo assunto, pois consegui resolver o problema de forma efetiva sem alterar qualquer configuração no banco de dados, a solução (ao meu ver mais correta) está nesse link: http://netbeando.blogspot.com/2009/03/broken-pipe-solucao-correta.html

Mas caso ela não resolva o seu problema, parta para algo mais radical como a solução abaixo:

Fiquei muito tempo tentando descobrir como resolver um problema que ocorria todos os dias em um sistema que ficava aguardando conexões de clientes através de um socket, o problema é que como as conexões eram esporádicas, ou seja, ficavam as vezes mais de 10 horas sem receber conexão alguma e no momento que algum cliente tentava se conectar depois deste período de inatividade ocorria o erro no socket com a mensagem "broken pipe", bom, tentei resolver de várias formas, mas infelizmente por uma série de motivos a única forma que resolveu efetivamente foi aumentando o timeout do próprio banco de dados. No meu caso eu estou utilizando o mysql, então se você acessar o prompt do mysql e digitar:

show variables

Serão mostradas todas as variáveis utilizadas por esse banco de dados, a que realmente interessa é a:

wait_timeout

Inicialmente essa variável está definida para 28800 , li sobre o assunto e me parece que definindo como ZERO as conexões do banco de dados ficam sem timeout, acabei não optando por essa opção, simplesmente aumentei esse timeout para que ficasse a minha conexão ativa por mais de 12h mesmo sem inatividade, resolveu 100% o problema.

Bom, agora você deve estar se perguntando como alterar o conteúdo desta variável, no meu caso, como o sistema operacional que esta instalado o sistema é um Linux, bastou acessar o arquivo /etc/mysql/my.cnf , editar com um editor de textos qualquer e trocar o valor da variável... claro tive que reiniciar o mysql depois.

T+

sábado, 31 de maio de 2008

JPA x Alterações (externas) na base de dados

Quebrei a cabeça muito tempo por um problema que estava acontecendo em um sistema que utiliza JPA para conexão com o banco de dados, o que ocorria era o seguinte, existem 2 sistemas separados que conectam na mesma base de dados e fazem alterações, o problema era que um não conseguia visualizar as alterações do outro, ou seja, digamos que um dos sistema seja para autorização de vendas e verifique o saldo de determinado cartão e o outro sistema a cada mês retornava o limite de crédito para esse cartão assim ele continuaria comprando normalmente no novo mês, o caso é que o sistema que autoriza as vendas não conseguia vizualiar a alteração de restituição do saldo feita pelo outro sistema, então o cartão embora tivesse saldo, pro sistema de autorização continuava sem... depois eu notei acontecia o mesmo problema se eu alterasse os registros diretamente no banco de dados, os sistemas não conseguiam fazer os selects e trazer os dados atualizados.... eis a solução adotada:

Nas classes das entidades mapeadas, bastou incluir um novo parâmetro nas namedqueries, coloquei em negrito esse novo parâmetro, veja como ficou um pedaço do código por exemplo:

@Entity
@Table(name = "cartoes")
@NamedQueries({@NamedQuery(name = "Cartoes.findByCodigo", query = "SELECT f FROM Cartoes c WHERE c.codigo = :codigo", hints=@QueryHint(name="toplink.refresh", value="true")), @NamedQuery(...})

public class Cartoes implements Serializable {...

Notou o "hints=@QueryHint(name="toplink.refresh", value="true")"? Simples não?

Porém, se você utilizou o createquery na "mão" poderia usar assim, por exemplo:

Query query = this.entityManager.createQuery("SELECT c FROM EmpresasProdutos c WHERE c.empresa.codigo = :empresa AND c.tipo=:produto").setHint("toplink.refresh", "true");

T+

terça-feira, 26 de fevereiro de 2008

NetBeans 6.0.1 - Herança visual

Finalmente existe a possibilidade de se conseguir fazer herança visual (dos forms) no NetBeans, não estou me referendo aos usuais templates que todos acabam mencionando... estou falando de herança mesmo, aquela que o Delphi oferece, ou seja, você cria um formulário padrão e depois herda as características deste formulário para outros, e quando você alterar o formulário padrão essas alterações são espelhadas nos seus "filhos", coisa que os templates não conseguem fazer.

Bom, segui fielmente o que contém nesse link http://wiki.netbeans.org/FaqFormExtendingForms

Mas pra tentar simplificar vou colocar os passos abaixo:

1) Crie um novo projeto
2) Crie um formulário que será o nosso padrão, pode ser um JFrame por exemplo, de o nome de BaseForm para ele e insira um método que retorne o JPanel vazio como um container, como no exemplo abaixo:

public Container getJPanel1() {
return jPanel1;
}

3) Insira os componentes que serão modelos para todos os formulários filhos
4) Insira um JPanel e deixe ele totalmente vazio
5) Você vai precisar criar uma classe chamada BaseFormBeanInfo e que o extends dela seja de SimpleBeanInfo, como no exemplo abaixo:

public class BaseFormBeanInfo extends java.beans.SimpleBeanInfo {
//public final static Class beanClass = BaseForm.class;
private BeanDescriptor beanDescriptor;

public BaseFormBeanInfo() {
super();
}

@Override
public BeanDescriptor getBeanDescriptor() {
if (beanDescriptor == null) {
// BaseForm é o formulário padrão
beanDescriptor = new BeanDescriptor(BaseForm.class);
// getJPanel1 é o nome do método que retorna o JPanel vazio que está no BaseForm
beanDescriptor.setValue("containerDelegate", "getJPanel1"); // g
}
return beanDescriptor;
}
}

ATENÇÃO: O nome BaseFormBeanInfo não é por acaso, tem que seguir esse padrão, caso o seu formulário padrão se chamasse PadraoForm a classe BeanInfo iria se chamar PadraoFormBeanInfo.

6) Compile o projeto
7) Vamos criar o formulário filho a partir do BaseForm, para isso crie um formulário do tipo "Formulário Bean" (BeanForm) e quando for solicitada qual é a superclasse informe "BaseForm" (sem as áspas é claro).
8) Pronto! Mas como nem tudo são flores, o que você vai visualizar no seu formulário filho é justamente aquele JPanel que foi inserido vazio na superclasse, é nele que você vai inserir os seus novos componentes, etc...

Agora você deve estar se perguntando... mas se eu tenho um botão de ok no BaseForm e quero mudar o seu modo de funcionamento, como poderia alterar no meu formulário herdado o código definido no BaseForm? Muito simples, no evento de click do botão no BaseForm você poderia colocar a chamada de um método seu, por exemplo:

cliqueOk();

Esse método você deve declarar como sendo protected dessa forma você redefine ele na sua classe herdada e ele passa a executar o código novo, caso contrário ele executa o código que foi definido na superclasse.

Se preferir faça download do projeto de exemplo aqui.

[]´s