1

Como Fiz o EncomendaZ 3.0 – Parte 1

Antes de mais nada, quer tirar dúvidas sobre este post? Acompanhe-me no Twitter: @marlonscarvalho. Agora, vamos ao que interessa. O EncomendaZ foi um projeto que surgiu meio que do nada. A primeira versão eu fiz só para aprender um pouco sobre programação com Swing. Aliás, eu sou fanzarço de programação desktop e não curto muito “programação orientada a tags”. A primeira versão você encontra até hoje no Google Code, neste endereço: http://code.google.com/p/encomendaz/. Foi uma versão sem muitas pretensões, mas acredito que já aconteceu com você também: você faz um programa, algumas pessoas começam a usar e elogiar mas você acha que podia ter feito melhor. E foi assim comigo. Resolvi, então, fazer uma nova versão, só que desta vez bem melhor.

O sucesso da versão 2.0 me fez pensar na versão 3.0. Fui bastante relutante em lançar ela, pois daria um trabalho monstro fazer. Mas eu fiz. E, desta vez, a motivação foi aprender ainda mais a programar para desktop, desta vez usando frameworks diferentes e padrões de projeto bastante conhecidos. Eu já tinha vontade de descrever todo o processo de criação desta versão. Sei que muitas pessoas também curtem programação desktop, mas não sabem por onde começar. Aliás, ultimamente você só encontra referências para programação Web. Parece que tudo é Web hoje em dia e sistemas desktop morreram. Pra mim, pura balela.

Eu vejo mais um mundo onde serviços estão na internet e aplicativos, seja desktop, mobile ou web, os consome. Tem aplicativos que são muito mais fáceis de serem usados no Desktop. São mais práticos, elegantes, tem mais funcionalidades, são rápidos e podem funcionar offline. O que é errado é criar aplicativos desktop “autocontidos”. Ou seja, tem seu próprio banco de dados, não compartilha dados com outros aplicativos. Enfim, falo dos “aplicativos ilha”: vivem em seu próprio mundo e esquecem o resto. Mas, hoje, todo mundo só pensa em fazer aplicativo pra browser, como se fosse a bala de prata. Estão errados.

O meu objetivo é criar uma sequência de posts descrevendo todo o processo criativo que levou à concepção da versão 3.0, que você pode usar através do Webstart, clicando aqui. O código fonte do EncomendaZ 3.0 está disponível no Bitbucket e você pode baixar, usar, brincar… Espero que estes posts sejam úteis para você.

Código fonte da camada de apresentação: https://bitbucket.org/alienlabz/encomendaz-swing
Código fonte do core: https://bitbucket.org/alienlabz/encomendaz-core

Primeiro, vamos listar as tecnologias envolvidas. São muitas:

  1. Maven para gerenciar o projeto;
  2. Eclipse Indigo como ambiente de desenvolvimento;
  3. Java/Swing para a camada de apresentação;
  4. Framework Demoiselle;
  5. Hibernate para persistência;
  6. HSQLDB para armazenar os dados;
  7. Velocity para geração dos templates de e-mail;
  8. Jasypt para criptografia de senhas e etc;
  9. Apache Commons E-mail para o envio de e-mail;
  10. Barbecue para a geração do código de barras;
  11. JasperReports para a geração dos relatórios;
  12. Jide OSS para alguns componentes de tela;
  13. HTTPClient da Apache para conexão com a internet;
  14. Quartz para o agendamento de tarefas;
  15. MigLayout para a criação de formulários;
  16. SwingX para componentes de tela;
  17. L2FProd para ter o componente de barra de ações lateral;
  18. Insubstantial para os temas Swing;
  19. JCalendar para ter um calendário bonito no Swing;
  20. JBusyComponent para ter um “Loading” tipo o Ajax em Web;
  21. Zeus JSCL para ter um componente mais amigável para exibir erros;
  22. Java WebStart para publicação.

Vou tentar justificar o uso de cada uma destas tecnologias. Ou não. 🙂 São muitas e talvez eu não consiga chegar até o final. Vou começar justificando o uso do Framework Demoiselle. Você conhece? Não? Pois saiba que você deveria dar uma chance a ele. E não foi só porque eu participei da equipe que o criou, mas porque é um ótimo framework, de fato. O Demoiselle teve sua concepção inicial no Serpro, mas hoje já é usado por diversas empresas, incluindo aí outros órgãos governamentais, como: TRT, MPU, Prodeb, Fundação Luís Eduardo Magalhães e por aí vai.

E estas empresas não o estão usando por imposição. Ninguém é obrigado a usar o Demoiselle. Usam porque gostaram e tecnicamente é um ótimo framework. Quer entrar em contato com a equipe do Demoiselle? Primeiro, use a lista de discussão. Depois, acesse o fórum. E também tem os @zyc, @wegneto, @e_saito e @Atiboni no Twitter para vocês tirarem dúvidas. 🙂

E como foi que o Demoiselle facilitou no EncomendaZ? Simples:

  • Injeção de Dependência com Weld é o bicho! 🙂 Nada de criar exaustivas fábricas;
  • As classes de template para CRUD diminuíram consideravelmente a quantidade de código para escrever;
  • O POM (Maven) parent do Demoiselle para aplicações Desktop simplificou a criação do projeto;
  • O controle de transações é fácil e extensível. Não fosse por isso, eu não teria conseguido resolver alguns problemarços que apareceram!
  • O ResourceBundle próprio do Demoiselle, com substituição de palavras-chave é uma mão na roda;
  • Já fornece algumas validações comuns no Brasil através do componente demoiselle-validation.

Eu poderia citar outras, mas estas aí já são suficientes. O que posso dizer é que o Demoiselle está funcionando rock-solid no EncomendaZ 3.0 e nenhum erro reportado até hoje foi proveniente dele. Contudo, tive alguns probleminhas e vou citar eles em breve. No próximo post, vou descrever o principal padrão de projeto que usei: Passive View. É um ótimo padrão e, em conjunto com o Demoiselle, forma a base do aplicativo.

DemoDroid++!

Vamos ver um pouco mais sobre o DemoDroid. Dessa vez, vou demonstrar só mais uma feature bem bacana. Para quem já programa para Android, já sabe que é necessário abrir manualmente as conexões com o banco de dados e gerenciar esta conexão. Já mostrei no post anterior que você não precisa mais fazer isso, pois já existe a classe EntityManager que trata tudo isto para você. Agora ficam umas perguntas para responder:

1. Quando abro um banco de dados, eu dou um nome a ele, como é feito isso agora?
R: Você pode fornecer um nome usando o seu arquivo de Manifest do Android (AndroidManifest.xml). Lá, você pode colocar qual o banco de dados e a versão.

<meta-data android:name="DATABASE_NAME" android:value="MeuBanco.db" />
<meta-data android:name="DATABASE_VERSION" android:value="2" />

2. Entendi. Mas, e se eu não informo isto no Manifest?
R: Será criado um banco de dados padrão, chamado Demoiselle.db.

3. Eu vi ali a versão e agora lembrei que eu usava a classe SQLiteOpenHelper do próprio Android. Eu estendia essa classe e depois sobrescrevia o método onUpgrade. E agora? Como faço?.
R: O DemoDroid vai prover umas três formas diferentes de você resolver isso. A primeira é bem simples. Você pode criar um método qualquer, mas que tem uma assinatura assim:

	public void databaseUpgrade(@Observes DatabaseUpgrade event) {
		Log.d("Persistence", "Verificada a necessidade de atualizar a Base de Dados");
	}

Toda vez que ocorrer a necessidade de atualizar a base de dados, este seu método será chamado. No objeto “event”, você poderá ver a versão antiga e a nova, além de ter o objeto SQLiteDatabase para fazer suas operações na base de dados.

4. Epa! Você falou em três ou mais! Quais são as outras formas?

R: Apressadinho. Eu já ia explicar. A segunda forma também é simples. Você pode criar uma classe que receberá esses eventos de outra forma. Veja:

@Upgrade(version = 4)
public class UpgradeToVersion4 implements UpgradeRequest {

	public void upgrade(SQLiteDatabase database) {
	}

}

Como funciona isso? Perceba que você usa a anotação @Upgrade e diz qual a versão. Imagine que um usuário pegou sua aplicação na versão 1 da base de dados. Alguns meses depois, ele atualiza a aplicação. Contudo, agora a base já está na versão 4. E agora? O DemoDroid vai procurar no seu classpath todas as classes que possuem a anotação @Upgrade e que implementa a interface UpgradeRequest. Ele irá executar as classes em sequência. Se tiver uma classe anotada com @Upgrade(version=2), ele vai chamar ela primeiro. Se tiver uma classe com a anotação @Upgrade(version=3), ela será chamada logo em seguida. Entendeu? Você fez um histórico de atualizações necessárias para cada versão. E elas serão executadas AUTOMATICAMENTE. Basta criar a classe como foi exemplificado acima!

5. Nem invente. Pode ir me dizendo as outras formas. Só disse duas até agora.
R: As outras formas ainda não foram implementadas mas estão no nosso backlog. A terceira ideia é realizar atualização a partir de um arquivo XML. A quarta opção é ter uma classe utilitária que ajudará a fazer a atualização sem usar comandos SQL.

E aí? Curtiu?

Android é com o DemoDroid!

Comprei um celular com Android e, a esta altura, isto já não é mais novidade para ninguém. Mudei de iPhone para Android por um motivo muito simples: odeio Objective-C. Ah, e também odeio a política de publicação de aplicativos da Apple. Ah, e também acho simplesmente um assalto ter que dar 60% do valor do meu aplicativo para eles. É, acho que agora acabei minha lista negra contra o iPhone. 🙂 Mas, no mais, eu gostava dele. Só que agora, achei um concorrente: Samsung Galaxy S. Sensacional.

Mas, cala a boca, Marlon. Você não criou esse post para se vangloriar de seu novo celular e nem para falar mal da Apple. Na verdade, eu queria falar do DemoDroid. Não, não tem nenhuma relação com culto ao Satanás. DemoDroid é a junção das ideias que vivenciei no desenvolvimento do projeto Demoiselle com o ambiente do Android. E surgiram várias coisas legais dessa brincadeira. Por enquanto, vou só dar uma pincelada em umas ideias. Depois, faço mais alguns posts com mais detalhes! Agora é só para você ficar com vontade.

Vamos lá. Para quem já programou em Android, sabe que existem algumas tarefas chatas de serem feitas. Abrir e fechar conexão com o banco de dados é uma delas. Usar Cursor, então… para quem veio do mundo Java e sempre usou Hibernate, sente coceiras quando vê que no Android você precisa voltar a escrever código SQL e iterar em um Cursor para obter os dados. Então, resolvi criar um conjunto bem pequeno de classes, de forma que não tivessem impacto muito grande, para facilitar isto. E aí minha classe da camada de persistência ficou com trechos de código assim:

public class TrackingPersistence extends SQLiteCrud<Tracking> {

	@Inject
	@SQLite
	private EntityManager entityManager;

	public List<Tracking> findNotDeliveredTrackings() {
		Query query = entityManager.createQuery(Tracking.class, "select * from tracking where has_arrived = 0 and send_date IS NULL");
		return (List<Tracking>) query.getResultList();
	}
}

Bem mais clean, né não? E é isso mesmo que você está pensando: usei um pouco da ideia do JPA. Perceba ali que injeto um EntityManager e qualifico para ser injetado um que trabalhe com SQLite. Injetado? Como assim? Tem CDI no Android? É, tem sim. Na verdade, é o Google Guice. Você pode usar ele através do projeto RoboGuice. Vê lá que também tem a interface Query, igual ao JPA. A diferença é que você precisa colocar um código SQL puro e não mais HQL ou JPQL. Eu sei, isso é chato. Mas é Android, lembre. Fazer um parser de uma linguagem intermediária para SQL nativo seria muito custoso para um dispositivo. Ficou curioso para ver a entidade Tracking? Vamos lá:

@Entity
@Table(name = "tracking")
public class Tracking {

	@Id
	public long id;

	public String code;

	public Date send_date;

	public boolean has_arrived;

	public boolean taxed = false;

	@Transient
	public boolean has_changed = false;

	@Transient
	public Status lastStatus;

}

Ahhhhhhhh! Espertão! Também copiou as anotações de campos, né? Exatamente. 🙂 E funciona igualzinho a como você já sabe em JPA. Uma diferença: aqui não resolvemos relacionamentos entre entidades. Aliás, eu sequer indico que você faça relacionamentos de entidades quando estiver programando em Android. Relacionamentos são custosos demais para serem carregados e sempre bastante imprevisíveis à medida que você aumenta esta hierarquia de dependência entre os objetos. Evite!

Agora, você deve estar se perguntando: eu sei que tenho que criar as tabelas com SQL. Mas, onde você faz isso? Não faço. Ao iniciar a aplicação pela primeira vez, o próprio DemoDroid vai descobrir suas classes anotadas com @Entity e vai criar as tabelas para você. Sim, você quer saber, e que classe SQLiteCrud é essa? Ela já fornece alguns métodos CRUD por padrão para você. São os tradicionais Insert, Update, Delete, Find e FindAll. Já vem tudo implementado para você. Na sua classe de persistência você só precisa implementar os métodos a mais que precisa, como no exemplo que passei.

Vamos a outra coisa bastante usada em Android: exibição de mensagens de sucesso ou falha pra o usuário. E no Android, a forma mais trivial é usar a classe Toast. Ela é responsável em exibir aquele balão que some automaticamente depois de um tempo. Como você usaria ele normalmente? Seria assim:

	Toast toast = Toast.makeText(context, "Meu Texto", Toast.LENGTH_SHORT);
	toast.show();

Mas, certamente, você fará uma classe utilitária para evitar proliferar este mesmo código por toda a sua aplicação, certo? Pensando nisso, porque não usar algo assim?

	@Inject
	@Toaster
	private MessageContext messageContext;

	public void saveException(CodeExistsException exception) {
		messageContext.add(R.string.error_code_exists);
	}

Você poderia passar como parâmetro para o método “add” também uma String, mas o mais normal é passar o ID da string que está no seu arquivo de Resource. Feito isto, pronto. Sua mensagem vai ser exibida. Em qualquer parte da sua classe basta fazer igualzinho ao que foi feito no método saveException, pois você já injetou o contexto de mensagens. E olha uma coisa mais legal ainda: usando o MesageContext, você pode parametrizar as mensagens. Caso você crie uma mensagem no seu arquivo de resource que seja assim: “Uma Mensagem para {0}”, basta fazer messageContext.add(R.string.mensagem, “Marlon”). Entendeu? Nos próximos posts, mais pitacos sobre o DemoDroid! AH! Se eu estou usando o DemoDroid em algum projeto? Claro, no EncomendaZ para Android: https://market.android.com/details?id=net.silvacarvalho.encomendaz