Como implementar paginação para listboxes com muitos elementos com o ZK Framework

Segue mais um post sobre o ZK Framework escrito pelo Marcos de Sousa.
Muito bom o post, e o ZK é bem legal tanbém, para saber mais sobre o ZK Framework podem dar uma olhada neste post,também escrito pelo Marcos.


Como implementar paginação para listboxes com muitos elementos

by Marcos de Sousa (Maputo - Mozambique)
13/06/2008

Versão

Eu testei os códigos fontes com ZK 2.4.0, pelo que pode usar ZK 2.4.0 e versões recentes

A Questão

O componente listbox é utilizada para exibir uma série de elementos em uma lista. Os componentes listbox e grid suportam a paginação intrinsecamente. Se você tem uma lista com muitos elementos, por exemplo 1.000.000 elementos, isto vai abrandar a sua aplicação web, ele pode potencialmente utilizar uma grande quantidade de memória no servidor, limitando o número de usuários que podem ser suportados em qualquer tempo. Isto é o que nós não queremos que aconteça. Portanto, vamos corrigi-lo.

A Solução

Paginação é a forma mais simples e comum de dividir grandes quantidades de dados em pedaços pequenos. Paginação é uma parte fundamental no desenho duma aplicação web, tanto do ponto de vista de Desenho de Interface como do ponto de vista do servidor (para processar grandes conjuntos de forma eficiente, sem causar atrasos nos serviços recurso). ZK tem um componente básico chamado Paging. O componente paging é usado para separar longo conteúdo em várias páginas. Para resolver o problema temos de especificar um componente paging explicitamente.

A. Criando as Páginas:

Eu irei revisitar o código fornecido em http://en.wikibooks.org/wiki/ZK/How-Tos#ZK_2.x.x_.2B_Spring_2.x.x_.2B_Hibernate_3.x_.2B_JUnit_Test

Primeiro, vamos ver como utilizar um componente listbox com paginação intrinsecamente:

1
2
3
4
5
6
7
8
9
10
<?xml version="1.0″ encoding="UTF-8?>
<window title="Listbox with Paging Intrinsically" border="normal" use="com.wikibook2.ui.EmployeeUI">
<listbox id="lstEmployee" width="350px" checkmark="true" mold="paging" pageSize="30″>
<listhead sizable="true">
<listheader label="ID" sort="auto" />
<listheader label="Full Name" sort="auto" />
<listheader label="User Name" sort="auto" />
</listhead>
</listbox>
</window>

Agora, nós queremos usar uma listbox com um componente paging explicitamente:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<?xml version="1.0″ encoding="UTF-8?>
 
<window title="Listbox with Paging Explicitly" border="normal" use="com.wikibook2.ui.EmployeeUI">
 
<listbox id="lstEmployee" width="350px" checkmark="true">
<listhead sizable="true">
<listheader label="ID" sort="auto" />
<listheader label="Full Name" sort="auto" />
<listheader label="User Name" sort="auto" />
</listhead>
</listbox>
<paging id="pagEmployee" pageSize="30″ />
 
</window>

A única diferença é, em vez de nós especificar “mold=“paging”” nós não especificamos nada, e em adição nós usamos o componente paging explicitamente “<paging id=“pagEmployee” pageSize=“30″/>“. É tudo no Desenho de Interface.

B. Código – Desenho de Interface:

Vamos dar uma olhadela para a classe EmployeeUI:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
package com.wikibook2.ui;
// Imports Omitted
public class EmployeeUI extends SimpleWindow implements AfterCompose {
private final String LST_EMPLOYEE = "lstEmployee";
private final String PAG_EMPLOYEE = "pagEmployee";
private final String MAN_EMPLOYEE = "employeeManager";
private GenericManager employeeManager;
public EmployeeUI() {
employeeManager = (GenericManager) SpringUtil.getBean(MAN_EMPLOYEE);
}
public void afterCompose() {
Paging pag = getPaging(PAG_EMPLOYEE);
pag.setTotalSize(employeeManager.count().intValue());
final int PAGE_SIZE = pag.getPageSize();
// Show Listbox with first PAGE_SIZE
redraw(0, PAGE_SIZE);
pag.addEventListener("onPaging", new EventListener() {
public void onEvent(Event event) {
PagingEvent pe = (PagingEvent) event;
int pgno = pe.getActivePage();
int ofs = pgno * PAGE_SIZE;
// Redraw current paging
redraw(ofs, PAGE_SIZE);
}
});
}
private void redraw(int firstResult, int maxResults) {
Listbox lst = getListbox(LST_EMPLOYEE);
lst.getItems().clear();
 
List<Employee> list = employeeManager.getAll(DetachedCriteria.forClass(Employee.class), firstResult, maxResults);
 
for (Employee employee : list) {
Listitem li = new Listitem();
li.setValue(employee);
li.appendChild(new Listcell("" + employee.getId()));
li.appendChild(new Listcell(employee.getFullname()));
li.appendChild(new Listcell(employee.getUsername()));
lst.appendChild(li);
}
}
}

Como você pode ver, a ideia principal é Estratégia Baseada em Consulta, onde resultados são colectados da base de dados quando necessário na medida que o utilizador vai navegando sobre as pequenas páginas e enviados para o cliente. Isto significa que uma nova consulta será executada sempre que o usuário navegar entre as páginas, claro que há uma sobrecarga no desempenho com esta abordagem. No entanto, devido ao menor uso de memória, esta solução é também mais escalável e geralmente, esta é a consideração importante quando se trata de aplicações Web. Com a implementação de AfterCompose, nós executamos algumas inicializações:

  • Definimos o número total de empregados
  • Desenhamos a listbox com os primeiros empregados na página inicial
  • Adicionamos o Evento onPaging para o componente paging

O evento onPaging, é enviado com uma instância de PagingEvent para o componente paging, depois, nós recuperamos a página activa (apartir de 0) e o índice dos primeiros empregados visíveis pela multiplicação da página activa pelo tamanho duma página.

Uma vez que sabemos qual é a página actual, nós redesenhamos a listbox; primeiro nós limpamos todos empregados e depois consultamos o novo pedaço de página de empregados. Lembre-se que, o AfterCompose é um pouco mais rápido, uma vez que não necessita de criar uma outra thread enquanto o evento onCreate é livre para suspender e retornar a execução.

C. Conclusão:

Este pequeno artigo introduziu-lhe o poder do componente paging, como implementar a paginação para listbox com bastante performance quando a listbox tiver muitos elementos.

Você pode encontrar as desvantagens de usar um componente paging externo ao listbox em http://en.wikibooks.org/wiki/ZK/How-Tos#How_to_implement_paging_for_listboxes_with_many_items

Espero que tenha gostado deste pequeno artigo e que este artigo o tenha influenciado para iniciar a utilizar a Framework ZK. No meu dia-a-dia a Framework ZK tem sido bastante produtiva no desenvolvimento de aplicações Web tanto para a intranet como para a internet.

Download

Pode baixar o projecto aqui.
Depois de fazer download do projecto, leia o “readme.pdf” para saber como lidar com o projecto wikibook2.

Sobre Marcos de Sousa

Marcos de Sousa, trabalha na área de desenvolvimento a mais de 5 anos. Trabalha como Desenvolvedor Sénior no Banco Comercial e de Investimentos (BCI Fomento), um dos maiores grupos financeiros em Moçambique. Estudou a Licenciatura em Informática (Universidade Eduardo Mondlane – Curso de Informática (5º ano)).
Junho 13, 2008
Maputo – Moçambique

Se você gostou deste post, lembre-se de assinar o RSS feed do blog, para ser notificado de novos posts!

Programa de afiliados da 37signals

A 37signals é o ambiente de trabalho dos sonhos de muita gente (logo depois do google :D ), eles desenvolveram alguns produtos bem legais que ajudam muita gente, todos tem uma opção de uso gratuito, e valores pagos por recursos adicionais.
Até ai tudo igual a 90% das empresas focadas em Web, mas eles ficaram mais famosos ainda depois de publicar o Getting Real (Versão em português aqui), um livro sobre como eles desenvolveram os produtos, que acabou virando uma bíblia para muita gente (a metodologia focada em KISS é realmente uma inspiração :D ).
Agora eles começaram com um programa de afiliados para que usuários dos produtos deles possam ganhar uns trocados contando para outras pessoas que gostam do que usam :D
Então, eu resolvi colocar aqueles links ali ao lado para quem ainda não conhece ainda dar uma olhada.

Eu acho incrível a idéia do Highrise, um mini CRM de verdade, nada daquelas ferramentas auto entituladas CRM de enviar SPAM, eles criaram uma ferramenta espetacular para ajudar a lembrar quais assuntos ja foram tratados com cada um dos seus contatos, podendo agrupar contatos (e os respectivos históricos) por empresa e/ou por tags. Isto já me ajudou bastante :D

No programa de afiliados também entraram o Basecamp, uma ferramenta para facilitar a comunicação dentro de projetos e gerenciamento dos mesmos, e o Backpack basicamente um gerenciador de tarefas e calendário de grupos. Mas estes dois eu só testei, nunca cheguei a usar de verdade.

PS.: sim, este post foi apenas para publicar os links para as apps com o meu referer, mas as ferramentas são boas mesmo (pelo menos o highrise que eu acho espetacular, as outras duas eu ouço falar muito bem) :D

Se você gostou deste post, lembre-se de assinar o RSS feed do blog, para ser notificado de novos posts!

O JavaPlanet reencarnou!

Vocês lembram do site que eu coloquei no ar a algum tempo atrás, o JavaPlanet que era um agregador de feeds de sites sobre java? um pouco antes de aparecer o InfoBlogs …
Pois é, o site não tinha muitos visitantes, então resolvi não continuar com ele no ar …
A algum tempo atrás o Franklin do Portal Java falou comigo e eu doei o pouco código que existia do JavaPlanet para ele incluir na nova versão do PortalJava toda escrita em Java que iria ao ar em algum tempo.
Pois é, o Portal Java hoje esta no ar nesta nova versão totalmente escrito em Java utilizando o JavaNuke se não estou enganado, e o JavaPlanet reencarnou no link “Agregador” do Portal Java!
Confiram neste endereço, o melhor agregador de Feeds sobre Java do Brasil, ou seja, o JavaPlanet reencarnado dentro do Portal Java :D

Se você gostou deste post, lembre-se de assinar o RSS feed do blog, para ser notificado de novos posts!

Orientação a objetos é fácil, as pessoas é que complicam

A idéia de escrever este post veio desta discussão no GUJ, que começou falando de testes unitários e terminou sobre orientação a objetos.
Então seguem as minhas opiniões.


As linguagens de programação mais modernas, ou pelo menos as mais utilizadas de hoje em dia são Orientadas a Objeto, as famosas linguagens OO, mas mesmo assim, a grande maior parte dos desenvolvedores parece não conseguir entender direito a tal da Orientação a Objeto.
Resolvi escrever este este post porque do alto do meu ego inflado, acredito conseguir entender corretamente OO e poder ajudar um pouco.
Então, leiam o post até o final, e depois se quiserem tirar dúvidas ou me xingar, é só deixar um comentário …

O primeiro erro que todos cometem ao iniciar em OO é achar que Orientação a Objetos é sobre classes, isto não faz nenhum sentido, Orientação a Objetos como o próprio nome diz, é sobre Objetos, então, qualquer coisa que não seja um objeto não é realmente importante quando se fala em Orientação a Objetos.
OK, mas por que todos caem no mesmo engano então? porque a grande maior parte das linguagens de programação orientadas a objeto, utilizam classes como moldes para objetos, e durante o desenvolvimento se cria os moldes, ja que os objetos só existem em tempo de execução nestas linguagens.
Quais linguagens não funcionam assim? Bom, agora me vem a cabeça SmallTalk, IO e Ruby, mas devem ter outras.
SmallTalk porque não existe realmente distinção entre “tempo de desenvolvimento” e “tempo de execução” em SmallTalk, tudo esta sempre executando.
IO porque não utiliza o conceiro de classes (a não ser que eu tenha entendido a linguagem errado) e sim objetos template.
E Ruby porque as classes em Ruby são objetos também, mas das três é a que mais se aproxima do “padrão” que citei antes.

Outro erro bastante comum, desta vez quando se utiliza alguma tecnologia de mapeamento Objeto/Relacional, é achar que objetos são tabelas, mapeamento Objeto/Relacional serve para salvar o estado de um objeto em um banco de dados relacional, apenas isto, um objeto do tipo Usuario por exemplo, não possui um atributo “grupo_id”, mas pode possuir um relacionamento com um objeto do tipo Grupo. Percebam que eu escrevi atributo e não campo, pois tabelas tem campos e linhas, objetos possuem atributos e métodos.

Uma coisa bastante comum, ainda utilizando mapeamento O/R é achar que um objeto possui os mesmos atributos que a tabela correspondente, mas neste caso até os nomes são diferentes, infelizmente nestes casos, um objeto precisa ter um atributo “id” que mapeia para a chave primária da tabela, mas um objeto não tem uma chave primária, ele tem apenas atributos.

Então, como solucionar estes problemas?
Bom, no geral, um objeto tem comportamento, e alguns atributos também, mas o importante em um objeto é o que ele faz e como ele faz.
Claro que existem objetos que não tem comportamento, objetos em um sistema são a representação binária de alguma coisa do mundo real, e existem coisas no mundo real que não tem comportamento, tem apenas atributos, como por exemplo mesas e cadeiras, mas exceto se você estiver mapeando um destes objetos no seu sistema, todos os objetos tem um comportamento.
Por exemplo, se você criar um objeto do tipo Usuário, se ele não possuir nenhum comportamento, com certeza o seu sistema esta construído de forma errada, pois pelo menos eu, não conheço nenhum usuário que fique parado como uma estátua o tempo todo, e se este for o caso, com certeza ele não é usuário de sistema nenhum, portanto ele não deveria existir no seu sistema.
A mesma coisa se aplica a um carro, você conhece algum carro que não se move? Que não tenha comportamento algum? A única desculpa para um carro que não tem comportamento algum é um sistema para um museu de carros, onde só importa a carcaça do carro e os atributos dele, principalmente o ano de fabricação.

Outra coisa que todos entendem errado é o padrão MVC (Model, View, Controller).
Na definição do padrão, o controlador esta la apenas como ponto de entrada, ele passa parâmetros para um método de um Model, pega o resultado disto e passa para uma View, se ele estiver fazendo mais do que isto, ele possui parte do código que deveria estar dentro do Model, por tanto, o seu Controller esta errado!

Beleza, mas se eu estou dizendo que todos cometem os mesmos erros, como eu posso dizer que OO é fácil então?
Porque a maioria aprende primeiro a programar de forma estrutural, e depois passa para orientação a objetos, e como as pessoas aprendem coisas novas utilizando como base suas experiências anteriores, utilizam os paradigmas procedurais para tentar programar orientado a objetos, esta é basicamente a raiz do problema.
Para tornar a vida de todos mais fácil, o primeiro contato com programação nos cursos e faculdades deveria ser com SmallTalk e não com portugol ou pascal.
Se você aprender primeiro orientação a objetos, conseguira passar para programação procedural com uma facilidade muito maior do que alguem que aprende primeiro programação procedural tentando aprender orientação a objetos.

O pior é que as linguagens de programação que não são 100% OO contribuem ainda mais para aumentar este problema, vamos pegar o Java como exemplo de uma linguagem não 100% OO.
“Mas me disseram que java era uma linguagem de programação OO”
Bom isto também é verdade, eu disse não 100% OO, não disse que não era OO.
Exemplos de coisas que não são OO em Java: tipos primitivos e métodos estáticos
Basicamente eu acho que na linguagem é só isto que não é OO, mas isto ja causa problemas o suficiente confundindo a cabeça de muita gente.
“Perai, métodos estáticos ficam dentro de classes, como podem não ser OO?”
Mérodos estáticos são uma forma porca de programação procedural dentro de uma linguagem OO que teve uma linguagem procedural como origem, como por exemplo o Java e o C++.
Métodos estáticos não fazem parte de uma classe, utilizam a classe apenas como namespace, o que é diferente de fazer parte.
Em um método estático, não é possível nem saber a qual classe ele pertence, como é possível tanto em object pascal quanto em Ruby, ja que estas não possuem métodos estáticos e sim métodos de classe.
E os tipos primitivos estes sim, não tem relação nenhuma com orientação a objetos, só estão la porque quando a linguagem foi criada não era possível fazer uma classe ter a mesma performance do que um tipo mapeado diretamente do processador da máquina, eles existem em Java por problemas de performance e não por serem Orientados a Objeto.

Alguns design patterns foram criados apenas para contornar limitações da pataforma (Exemplo prático, com um banco de dados OO decente não seria necessário criar o pattern DTO), da mesma forma algumas das regras sobre a utilização de OO foram criadas apenas porque a maioria das pessoas não entende OO, como a regra que diz favoreça composição em vez de herança.
Este é um engano terrível cometido por muitas pessoas que eu não consigo entender.
Muita gente acha que estender uma classe é uma forma de compartilhar código, por exemplo:
Existe uma entidade no sistema de nome Cliente, e em algum momento é necessário criar um ClienteDependente que vai possuir todos os mesmos atributos de cliente mais um que aponta para o responsável, não faz sentido algum fazer ClienteDependente estender Cliente para compartilhar este código, porque o comportamento deles não é o mesmo, por exemplo, ClienteDependente não paga a conta, mas Cliente sim, neste caso seria melhor refatorar o sistema e criar uma entidade que pudesse realizar compras (Ou criar objetos do tipo Compra se o sistema foi bem modelado), e fazer com que Cliente e ClienteDependente estendessem desta, pois neste caso elas estariam realmente compartilhando o comportamento e não apenas evitando algum código aparentemente repetido.
Estender uma classe é estender o comportamento, ou seja, só faz sentido estender o comportamento se a classe “filha” tiver todo o comportamento da classe “pai”, ou seja, é um relacionamento o tipo “é um”. Mas como quase ninguém consegue entender que estender uma classe estende o comportamento (não me parece uma coisa tão complexa assim para se entender), foi criada esta regra que diz: Não use herança, use composição. Simplesmente para evitar que pessoas façam porcaria por não entender conceitos que são estupidamente simples, mas que todos tem mania de complicar.

Outro erro bastante comum é tentar colocar em uma classe apenas o comportamento de todo o sistema, se for para fazer isto, utilize programação procedural, pois você vai estar utilizando a classe apenas como namespace mesmo, não vai nem lembrar que em tempo de execução estara trabalhando com diversos objetos criados a partir daquela forma.

Orientação a objetos é simples, é um paradigma de desenvolvimento que modela um sistema transformando conceitos do mundo real como objetos que colaboram entre si para atingir um objetivo.
Acho que o nome Objeto pode ajudar a confundir boa parte das pessoas, pois em um sistema OO, Compra pode ser um tipo de Objetos, mas no mundo real, compra não é um objeto. Mas para resolver isto eu simplesmente assumo que qualquer um que queira ser um programador precisa ter capacidade para trabalhar com abstrações, não tenho uma explicação melhor para alguem que não consegue entender que Compra pode ser um tipo de Objeto em um sistema OO, assim como Viajem também pode ser um tipo de Objeto (estou utilizando “Tipo de Objeto” em vez de classe porque o que importa em um sistema OO são as instâncias e não as classes) dependendo do problema a ser resolvido.

Acho que são estes os erros mais comuns na orientação a objetos, lendo isto você não concorda comigo? OO é simples, as pessoas é que complicam!
Você lembra de algum outro erro muito comum em OO? deixe um comentário.
Se eu lembrar de mais coisas simples que as pessoas tem mania de complicar eu escrevo outro post.

Se você gostou deste post, lembre-se de assinar o RSS feed do blog, para ser notificado de novos posts!