sexta-feira, 25 de novembro de 2011

Usando padrão strategy para implementar método equals


Nos últimos anos quando preciso implementar o método equals e hashCode de uma classe de domínio da aplicação o processo é o mesmo: Crtl+C e Crtl+V.

Hoje finalmente encheu o saco ;D

Por que não codificar a parte chata e que não muda em apenas uma classe?
E nas outras codificaríamos apenas o que importa, que é como diferenciar dois objetos não-nulos da mesma classe.

Problema:
"Como implementar o método equals de forma elegante seguindo o princípio DRY?"

Com certeza existem formas diferentes de resolver a questão acima. Vou simplesmente postar como eu fiz. Se alguém quiser contribuir com algo relativo ao assunto, favor postar nos comentários.

Usei o padrão strategy, que permite encapsular a parte de um algoritmo que não muda numa classe abstrata e as partes que variam são implementadas em subclasses.

Aqui temos a classe abstrata:

O método abstrato isEquals encapsula a parte do equals que varia e trata a questão primordial levantada anteriormente: como diferenciar objetos não nulos da mesma classe.

Abaixo um exemplo de utilização na implementação do método equals de uma classe chamada CategoriaIdade.



Nesta classe, por questão de simplicidade considerei que basta comparar a propriedade (id) para testar a igualdade dos objetos.

É usada a classe EqualsBuider da biblioteca commons-lang da Apache Software Foundation para fazer comparações de igualdade entre os atributos dos objetos.

segunda-feira, 14 de março de 2011

Problema usando Maven + Eclipse WTP

Hoje pela manhã passei por um velho problema. Ao recompilar meu projeto web usando a tarefa test-compile do Maven, por algum motivo o WTP do Eclipse sobrescrevia os resources da minha aplicação com os test-resources.

Problema:
"sobrescrita de resources por test-resources ao fazer deploy de aplicação web"

Eu já tinha passado por isso antes e resolvido, mas fazia tanto tempo que nem me lembrava mais onde era a configuração.

Googlando um pouco descobri o artigo Integrate the Eclipse Web Tools Platform and Maven e finalmente pude resolver.

O problema ocorre por causa de uma configuração no arquivo
.settings/org.eclipse.wst.common.component
, encontrado dentro da pasta do projeto. Deve-se retirar a linha que indica que os recursos de testes devem ser copiados para o deploy-path. Confira como ficou meu arquivo na imagem abaixo.

Pronto! Rode um project clean do Eclipse, limpe o servidor, rode o test-compile (outras tarefas podem ser necesárias dependendo do seu projeto) e finalmente rode sua aplicação!

sexta-feira, 4 de março de 2011

Convertendo arquivos do microsoft office para PDF em Java

PROBLEMA:
Como converter um arquivo do MS-Office para o formato Adobe PDF de dentro de uma aplicação Java?

Depois de procurar um pouco e ler sobre bibliotecas como iText e POI, vou resumir aqui o que pude aprender.

A maioria das "soluções" que encontrei na web ou são propagandas de produtos comerciais ou são simples demais (por não converterem corretamente coisas básicas, como imagens e/ou tabelas). Um problema recorrente em muitos fóruns é a desinformação. Muitas postagens indicam bibliotecas como iText e o POI para resolver o problema.

O iText é uma biblioteca livre usada para criar e/ou alterar arquivos PDF's existentes. É o caminho quando se trata de juntar arquivos PDF em um único documento, por exemplo.

O POI é um projeto da Apache Software Foundation e também tem por objetivo criar e/ou editar documentos do MS Office.

Ou seja, se alguém soubesse como mapear arquivos do Office para PDF, provavelmente usaria essas duas bibliotecas para implementar o algoritmo de conversão. Falando de forma mais enfática:

"iText ou POI não convertem diretamente um arquivo do ms office para PDF."


JODConverter

Um projeto livre que trata o problema e que se mostrou o mais confiável(pelo menos em termos de suporte à conversão) é o JODConverter . Este projeto fornece uma biblioteca java que delega para o OpenOffice a tarefa de converter o arquivo.

Bom, quem já usou o OpenOffice para abrir documentos do Word ou Excel sabe que nem sempre a conversão é perfeita, principalmente em relação a versões mais recentes do MS-Office. Entretanto, a conversão feita pelo OpenOffice é talvez a melhor que existe no mercado (livre e pago).

Para fazer um teste rápido, siga os passos:

1) Fazer download do JODConverter e adicionar ao classpath da sua aplicação.
Pra quem usa Maven:

<dependency>
<groupid>com.artofsolving</groupid>
<artifactid>jodconverter</artifactid>
<version>2.2.1</version>
</dependency>


2) Iniciar OpenOffice em uma porta da máquina.
No Linux, abrir um terminal e executar o comando:

/usr/bin/soffice "-accept=socket,host=localhost,port=8100;urp;StarOffice.ServiceManager" -nologo -headless -nofirststartwizard &

* Repare que a porta usada é a 8100.
** Se o executável do OpenOffice (soffice) na sua instalação estiver em outra pasta, modifique o comando.

3) Rodar o programa de teste.
Convertendo um arquivo .doc para .pdf.

public class TestJODConverter {
public static void main(String[] args) throws ConnectException {
final File inputFile = new File("/home/meu_user/meu_documento.doc");
final File outputFile = new File("/home/meu_user/meu_novo_documento.pdf");

// connect to an OpenOffice.org instance running on port 8100
final OpenOfficeConnection connection = new SocketOpenOfficeConnection(8100);
connection.connect();

// convert
final DocumentConverter converter = new OpenOfficeDocumentConverter(connection);
converter.convert(inputFile, outputFile);

// close the connection
connection.disconnect();

}
}

Se ao invés de trabalhar com "arquivos", você precise converter para bytes use o exemplo do código abaixo:

public class TestJODConverterByteArray {
public static void main(String[] args) throws ConnectException {
final File inputFile = new File("/home/meu_user/meu_documento.doc");
final InputStream inputStream = new FileInputStream(inputFile);

final ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();

final OpenOfficeConnection connection = new SocketOpenOfficeConnection(8100);
connection.connect();

// convert
final DocumentConverter converter =
new StreamOpenOfficeDocumentConverter(connection);
final DocumentFormat inputFormat =
new DocumentFormat("Microsoft Word", DocumentFamily.TEXT,
"application/msword", "doc");
final DocumentFormat outputFormat =
new DocumentFormat("Portable Document Format", "application/pdf", "pdf");
converter.convert(inputStream, inputFormat, byteArrayOutputStream, outputFormat);

// close the connection
connection.disconnect();
//
inputStream.close();
//
byteArrayOutputStream.flush();
byteArrayOutputStream.close();
// faz algo com os bytes - como enviar para um cliente
System.out.println(byteArrayOutputStream.toByteArray());

}
}

Concluindo

No momento, minha pesquisa terminou por aqui.
Não sabemos se vamos adotar o JODConverter. Na verdade, estamos tentando matar esse problema na raiz: os requisitos :D

Se não conseguirmos, posto aqui que solução adotamos.