Setando valor em atributo privado de um objeto

O uso de reflection é um recurso extremamente útil quando se desenvolve frameworks. Quando surge a necessidade de se alterar um valor de um atributo privado de um objeto (assim como o hibernate também faz para injetar valores do banco mapeados), mas ao tentar fazer isso, era lançado a exception (java.lang.IllegalAccessException).
Para resolver esse problema, deve-se fazer uso do método setAccessible da classe Field, o qual “permite” o acesso ao atributo por reflection.
Segue um exemplo:

Class<?> c = Pessoa.class;
Object obj = c.getConstructor(new Class[]{}).newInstance();
Field field = c.getDeclaredField("nome");
field.setAccessible(true);
field.set(obj, "fulano");
System.out.println( ((Pessoa)obj).getNome() );

Outro detalhe importante, se usar c.getField(“nome”) para um atributo privado, será lançada a exception java.lang.NoSuchFieldException. Deve-se usar getDeclaredField.

 

Diferença entre os padrões Adapter e Proxy

Quando a utilização dos padröes Adapter e Proxy do GoF, é comum algumas confusões sobre suas aplicações. São padrões que ajudam a resolver vários problemas, oferecem a flexibilidade de mudar a composição em tempo de execução.
Os dois padrões possuem princípios semelhantes, de encapsular a utilização de um serviço. Mas os objetivos de cada um são diferentes.
O Adapter é um padrão estrutural utilizado quando a classe/interface de um serviço não possui a interface da maneira que o cliente espera e que não pode ser alterada. Sendo assim, é criado uma classe que converte uma existente para nova interface. É um padrão normalmente aplicado em sistemas legados, ou pra desacoplar algum framework.

Nesse exemplo, ao invés do cliente utilizar a classe GeradorLegado, ele utiliza a interface Gerador e a classe GeradorAdapter. Futuramente, quando o GeradorLegado for descartado, basta a nova classe implementar a interface Gerador.

O Proxy é uma classe que funciona como interface de um serviço para a classe cliente. Tem a característica e o objetivo de alterar o comportamento da classe de serviço implementada. Pode ser utilizada em vários casos como conexões de redes, tratamento de arquivos e inclusive em conjunto com o padrão DAO pra logs de auditoria.

No exemplo, o cliente faz uso da interface Gerador, que pode ser uma instância do GeradorProxy, o qual vai utilizar o método do GeradorImpl que é a classe de serviço, mas vai alterar o comportamento (com rotinas antes ou/e depois da utilização do metodo gerarAlgo() do serviço).
A principal diferença entre os padrões é que proposta do proxy é de alterar o comportamento do serviço mas preservar a interface, enquanto o Adapter muda a interface do serviço e preserva seu comportamento.
O cliente pode usar o Proxy ou diretamente o serviço (principalmente usando injeção de dependências), pois ambos implementam a mesma interface e, já com o Adapter o cliente vai sempre usar o Adaptador.
No uso do Adapter, geralmente é quando um serviço já esta definido e implementado e deve ser utilizado. No caso do Proxy, tanto o serviço quanto a interface pode já estar definida e sendo utilizada, mas é necessário alterar o comportamento do serviço, sem alterar sua implementação.

Casos de uso: diferenças entre include, extend e generalização

Vejo muitas situações onde alguns confundem muito o uso de relacionamentos em casos de uso, principalmente com include e extend.

Diagramas de casos de uso servem para descrever cenários de uma solução a ser desenvolvida, e interações dos usuários (atores) com funcionalidades (casos de uso, conhecidos também como UC) no sistema.  Pode-se relacionar o conceito de casos de uso com o conceito de estórias de usuários em scrum/XP.

O ator, na minha opinião é uma definição incorreta, pois o termo ator representa um indivíduo, e em UC o ator seria mais uma função, um papel, ou uma responsabilidade, que pode ser exercida por mais de uma pessoa (Ex. Cliente ao invés de Zezinho). Bom, mas isso é uma outra conversa.

Os UC, geralmente se relacionam com os atores, mas podem se relacionar também com outros UC. Até o UML 1.2, existia 2 relacionamentos entre UC: <<uses>> e <<extends>>. A partir do UML 1.3, existe 3 formas de relacionamento: inclusão (esteriótipo <<include>>), extenção (esteriótipo <<extend>>) e generalização.

O uso de <<include>> veio para substituir o <<uses>> da versão 1.1, e é usado quando casos compartilham comportamento comum com outros UC. Por isso até pode, mas não faz muito sentido um UC incluir somente um UC, pois não haverá compartilhamento e o conceito de “reutilização”, pois o UC incluído terá obrigatoriamente tal comportamento incluído.

O uso de <<extend>> é a utilização inversa da inclusão, e pode (não necessariamente) alterar o comportamento do UC que foi estendido. E nesse caso não tem problema conceitual em um UC estender somente um UC.

Segue um exemplo de extend e include. No caso seria um cenário onde o Vendedor tira um pedido para um cliente e ao tirar o pedido, ele pode ou não, dependendo do valor do pedido ou forma de pagamento, consultar o SPC e ao tirar o pedido, será feito a verificação de pagamentos em atrasos do cliente. No caso o Entregador fará a entrega do pedido, mas também será feito a verificação de pagamentos em atrasos, reutilizando a especificação dessa funcionalidade.

Quanto a generalização, foi introduzida a partir do UML 1.3, que é representada pela setinha fechada, é semelhante e muito facilmente confundido com o <<extend>>, acredito eu que pelo conceito de herança das linguagens de programação. Mas a generalização indica uma variação de outro UC. Uma alternativa ao uso de generalização é descrever um outro diagrama com o novo cenário. No exemplo de generalização abaixo, retrata dois cenários de pagamentos, em um só diagrama.

É muito importante lembrar que o grande valor dos casos de usos não estão no diagrama, e sim, na especificação (conteúdo/descrição) de cada UC, e existe uma metodologia para descrever os casos de uso, mas isso é assunto para um outro artigo.

Apache httpd 2 e Tomcat com AJP

Uma das maneiras de integrar o apache http com o Tomcat (ou outro servidor como Jetty, Jboss, Glassfish, …) é usando o proxy protocolo AJP, onde permite que o apache receba a requisição e a repasse para o tomcat, o qual pode, inclusive ficar em uma rede interna, atrás de um firewall.

Como exemplo dessa integração, segue os passos:

No apache, cria-se um novo arquivo em /etc/apache2/sites-available/ com um nome qualquer (ex. ajp_tomcat), com o seguinte conteudo:


Listen 9000
NameVirtualHost *:9000
<VirtualHost *:9000>
ServerName localhost
ErrorLog /var/log/apache2/ajp.error.log
CustomLog /var/log/apache2/ajp.log combined
<Proxy *>
AddDefaultCharset Off
Order deny,allow
Allow from all
</Proxy>
ProxyPass / ajp://localhost:8009/
ProxyPassReverse / ajp://localhost:8009/
</VirtualHost>

Onde:

  • 9000 é a porta que o apache vai atender as requisições a ser passadas para o tomcat.
  • ajp://localhost:8009/ é o servidor onde está o tomcat rodando (no caso na mesma máquina do httpd) e porta do AJP que é configurada em server.xml (padrão é 8009)

Agora precisa carregar o modulo de proxy do ajp do httpd.
# a2enmod proxy_ajp

E agora habilitar a configuração do arquivo criado.
# a2ensite ajp_tomcat

Pronto, agora só reiniciar o httpd.
# /etc/init.d/apache2 force-reload

E acessar http://localhost:9000/

Pode-se usar desse recurso para, por exemplo, fazer o tomcat escutar na porta 80, configurando por domínio/subdomínio específico. Outra utilização desse recurso é para fazer balanceamento de carga para requisições no servidor de aplicações.

Virtualização: HD adicional no WinXP

VirtualBox é um ótimo software de virtualização para máquinas experimentais e testes, sem afetar a máquina real. Em casos que criamos uma máquina virtual com Windows XP, a sugestão do virtualbox é de um virtual HD virtual muito pequeno (4Gb), e normalmente no decorrer do uso, temos a necessidade de mais espaço. Ao criar um HD virtual adicional, o Windows não o detecta automaticamente, e não aparece a unidade do HD novo em “Meu Computador”.

O que acontece é que o Windows detecta o HD novo mas não mostra pois não está formatado. Para formatar o HD novo no windows… segue os passos:

– Adicione o Disco Rigido Virtual pelo gerenciador de discos virtuais do virtualbox

– Vincule a maquina virtual que se deseja adicionar.

– Inicie o windows (no virtualbox)

Agora no windows XP virtual…

– Abra o painel de controle -> Ferramentas administrativas -> Gerenciamento do computador -> Armazenamento -> Gerenciamento de disco

– Agora no Disco 1 (disco zero é o C:) crie a nova partição e a formate.

Pronto! Vai aparecer a nova partição no “Meu Computador” do novo HD, pronta pra ser usada.

A mesma solução vale para o VMware também.

PostgreSQL: migrando de LATIN1 pra UTF-8

Para migração de bases, de LATIN1 pra UTF8 no postgresql, não existe uma ferramenta pronta para tal tarefa. Para tal, foi desenvolvido um roteiro (testado em um servidor RedHat5 e Debian 5 com PostgreSQL 8.1 em uma base de em torno de 2 Gb).
Recomendado que teste em um ambiente separado antes de aplicar o procedimento produção.

Primeiro, pare todos os serviços que utilizam o banco (ex. apache/php, tomcat, jboss) para não ter o risco de nenhum usuários alterar o banco durante o processo.
Nos comandos abaixo, substitua:
usuario_banco = usuário dono do banco, com permissões de apagar e criar bancos
meu_banco = o banco que vc quer fazer a migração

fazer um backup em texto plano

/usr/bin/pg_dump -i -h localhost -U usuario_banco -F p -D -v -f bancoL.sql meu_banco

Aqui está o segredo. Use o comando iconv para conversão:

iconv -f iso-8859-1 -t utf-8 bancoL.sql > bancoU.sql

Abra o arquivo bancoU.sql e no inicio, por volta da linha 7, onde tem “SET client_encoding = ‘LATIN1’;” troque LATIN1 por UTF8.

Com banco fazer:

Faça um backup, por garantia.
pg_dump -U usuario_banco -i -F c -b -f banco.backup meu_banco

Agora apague o banco inteiro
dropdb -h localhost -U usuario_banco meu_banco

crie-o em UTF8
createdb -h localhost -E UTF8 -U usuario_banco meu_banco

e agora restaure o banco convertido.
psql -h localhost -U usuario_banco -d meu_banco < bancoU.sql

caso use em seus SQL a função TO_ASCII, com UTF-8 ela não irã funcionar. Veja aqui a alternativa em um artigo passado.

MySql em rede

O banco MySql, por padrão, é configurado para permitir acesso somente da máquina local (onde está instalado). Caso acesse de outra máquina, ele retorna um erro de acesso não autorizado (mesmo estando com usuário/senha correto). Para liberar acesso para  todas as máquinas da rede, edite o arquivo /etc/mysql/my.cnf  e procure a seguinte linha

bind-address = 127.0.0.1

agora a comente ou a apague.
reinicie o mysql

/etc/init.d/mysql restart

Agora o mysql vai aceitar conexão pela rede.
Mas tem um problema. Ele vai aceitar conexão de qualquer máquina, e isso pode gerar problemas de segurança (caso tenha várias interfaces de rede), então no caso o recomendável seria liberar acesso somente para a rede interna (ex: 192.168.1.*). Para isso, foi usado o portmap, ou seja, adicione as seguintes linhas no fim do arquivo /etc/host.allow

mysqld : 192.168.1.0/255.255.255.0 : allow
mysqld : ALL : deny

e reinicie o portmap

/etc/init.d/portmap restart

Pronto.

PostgreSQL: função TO_ASCII em banco UTF-8

A função TO_ASCII no postgresql é muito útil principalmente para buscas onde se quer ignorar acentos em string. Ela funciona bem quando o banco de dados estiver em LATIN1 por exemplo.

SELECT TO_ASCII('tchê'); -- retorna 'tche'

mas quando usamos ela em um banco UTF8 retorna o erro “conversão de condificação de UTF8 para ASCII não é suportada”.

Para contornar esse problema, cria-se, uma função de banco onde podemos chamar de SEM_ACENTO, para usar no lugar da TO_ASCII.

CREATE OR REPLACE FUNCTION SEM_ACENTO(text)
RETURNS text AS
$BODY$
select
translate($1,'áàâãäéèêëíìïóòôõöúùûüÁÀÂÃÄÉÈÊËÍÌÏÓÒÔÕÖÚÙÛÜçÇ',
        'aaaaaeeeeiiiooooouuuuAAAAAEEEEIIIOOOOOUUUUcC');
$BODY$
LANGUAGE 'sql' IMMUTABLE STRICT;

Tamanho das tabelas no PostgreSQL

Em muitos casos é preciso saber o espaço em que as tabelas do banco de dados estão utilizando em disco, para fins de monitoramento e decisão de estruturação de banco. Para tal tarefa no PostgreSQL o comando abaixo resolve o problema.

SELECT esquema, tabela,
       pg_size_pretty(pg_relation_size(esq_tab)) AS tamanho,
       pg_size_pretty(pg_total_relation_size(esq_tab)) AS tamanho_total
  FROM (SELECT tablename AS tabela,
               schemaname AS esquema,
               schemaname||'.'||tablename AS esq_tab
          FROM pg_catalog.pg_tables
         WHERE schemaname NOT
            IN ('pg_catalog', 'information_schema', 'pg_toast') ) AS x
 ORDER BY pg_total_relation_size(esq_tab) DESC;

a coluna tamanho mostra o tamanho que os registros (tuplas) da tabela está ocupando no disco, e a coluna tamanho_total inclui também os TOASTs e os índices associados à tabela.

Com essa consulta, é possível inclusive montar scripts (em shellscript, perl, python, groovy, etc..) de monitoramento do banco, por exemplo: caso a tabela tal, ou a soma de todas as tabelas chegar a X Mb, envie um email de alerta. Outra utilização seria de geração de indicadores para análise de tendência da expansão do banco.