Objetivos

Referências complementares

Conceito

O que são PostLoad Processors?

PostLoad Processors, numa tradução livre, seriam “processadores pós carregamento”. Eles permitem realizar processamentos adicionais após o carregamento de um conjunto de informações, as quais, no contexto do Lumis surgem através dos sources. Que processamentos adicionais seriam esses? Modificar o valor de um campo, criar ou remover um campo, permitir que uma linha seja exibida ou não, dentre outras possibilidades.

Por exemplo, dado um conjunto de dados, gostariamos de excluir aqueles que são menores que uma determinada data. Se estes dados estiverem vindo de um banco de dados, podemos alterar diretamente a consulta SQL e realizar esse filtro. Entretanto, nem sempre temos essa opção. Para isso, podemos implementar um PostLoad Processor que exclua todos os registros que tiverem o campo de data menor do que o desejado.

Os PostLoad Processors podem ser aplicados em interfaces que contenham dados tabulares, por exemplo: 
lum_list, lum_adminList,lum_advancedTabularData, lum_tabularData.

Como declarar um PostLoad Processor?

Como foi dito, um PostLoad Processor permite modificar os registros que o seu source traz. Por essa razão, a declaração de um PostLoad Processor ocorre dentro da tag source:

<source>
    <postLoadProcessors>
        <postLoadProcessor className="caminho.completo.da.classe" />
    </postLoadProcessors>
</source>
 

Eis um exemplo completo de como poderíamos declarar um PostLoad Processo no arquivo duidefinition:

<interface id="candidatos">
    <sources>
        <source id="candidatos">
	    <fields>
	       <field id="NOME_CANDIDATO" />
	       <field id="porcentagemVotos" name="Porcentagem de Votos para o Candidato" externalData="true"/>
	    </fields>
	    <postLoadProcessors>
		<postLoadProcessor className="br.com.lumis.artigos.postload.NomeDoPostLoadProcessor" />
	    </postLoadProcessors>
	</source>
    </sources>
</interface>

Note que podemos definir mais de um PostLoad Processor por source, bastando para isso adicionar mais uma tag postLoadProcessor com a respectiva classe. A ordem com que o Lumis irá chamar cada PostLoad Processor será pela ordem de declaração deles. Poderiamos utilizar mais de um PostLoad Processor para separar melhor as responsabilidades e manter o código mais coeso.

É importante entender que o ciclo de vida de um PostLoad Processor inicia após o Lumis ter obtido todos os dados do seu source, e termina antes do Lumis renderizar esses dados na tela.

Para implementar um PostLoad Processor, devemos criar uma classe Java que implemente a interface IPostLoadProcessor. Esta interface contém apenas um método, como você pode ver a seguir: 

public interface IPostLoadProcessor {	
	void processSource(SessionConfig sessionConfig, Source source, 
		Node parametersNode, ITransaction transaction) throws PortalException;
}

Exemplos

Exemplo de implementação removendo um registro do source

Imagine o cenário onde você possui uma interface que lista os usuários do seu sistema. Entretanto, uma nova regra de negócio surgiu e o cliente gostaria que somente fossem listados os usuários que possuem destaque dentro do sistema. Essa regra de destaque poderia envolver vários fatores, por exemplo, quantidade de comentários, quantidade de acesso, popularidade etc. Neste caso, poderiamos criar um PostLoad Processor que iria iterar por cada usuário, removendo aqueles que não possuem destaque. O código a seguir mostra um exemplo de como isso poderia ser feito. Inicialmente obtemos os dados tabulares através da chamada a source.getData(). Logo em seguida, obtemos um objeto Iterator para iterar sobre cada registro existente. Feito isso, obtemos o valor do campo “ID_USUARIO”, que representaria a chave primária do source. Note que com o comando row.get, podemos obter o valor de qualquer campo disponível no source. Após obter o campo, verificamos se o usuário está em destaque. Caso ele não esteja, chamamos  iterator.remove(), fazendo com que aquele registro seja removido. Note que o método isUsuarioEmDestaque() não foi exibido, pois o foco deste exemplo era demonstrar como um registro pode ser removido dinamicamente através de um PostLoad Processor.  

package br.com.lumis.artigos.postload;
// imports omitidos
public class RemoverUsuariosSemDestaquePostLoadProcessor implements IPostLoadProcessor {

	public void processSource(SessionConfig sessionConfig, Source source, Node parametersNode, ITransaction transaction)
			throws PortalException {
		TabularData tabularData = (TabularData)source.getData();
		Iterator iterator = tabularData.getRows().iterator();
		
		while (iterator.hasNext()) {
			ISourceData row = (ISourceData)iterator.next();
			
			String idUsuario= (String)row.get("ID_USUARIO");
			if (! isUsuarioEmDestaque(idUsuario)) {
				iterator.remove();
			}
		}
	}
}
Para utilizar este PostLoad Processor, a declaração no source ficaria da seguinte maneira:
<sources>
    <source id="pessoaFisica">
        <postLoadProcessors>
            <postLoadProcessor className="br.com.lumis.artigos.postload.AdicionaCandidatoPostLoadProcessor" />
        </postLoadProcessors>
    </source>
</sources>

No exemplo anterior, vimos como poderiamos excluir um registro dinamicamente. Agora, vamos ver o caso em que desejamos modificar uma das colunas de um determinado registro. Imagine o cenário de uma votação. Dentre uma lista de candidatos, um usuário pode votar naquele que mais o agrada. Numa tela inicial, o usuário realiza a votação e logo em seguida, ele é redirecionado para uma tela contendo a porcentagem de votos para cada candidato. Entretanto, o source só nos traz a informação da quantidade de votos de cada candidato e o total de votos existentes. Para mostrarmos a porcentagem, precisamos dividir essa quantidade de votos de cada candidato pelo total de votos existentes.
Como esse porcentagem será calculada dinamicamente através do nosso PostLoad Processor, podemos declarar no nosso source um campo externalData, indicando que o valor dele não será populado através da base de dados definida no source.

<field id="porcentagemVotos" name="Porcentagem de Votos para o Candidato" dataType="string" externalData="true" />

Feito isso, implementamos nosso PostLoad Processor de maneira similar ao exemplo anterior, com a diferença de que agora utilizamos o comando row.put("porcentagemVotos", votePercent) para modificar o valor do campo externalData.

Neste exemplo modificamos um campo externalData, mas nada impede você de modificar qualquer outro campo do seu source.

Exemplo de implementação modificando uma coluna do source

package br.com.lumis.artigos.postload;
// imports omitidos
public class CalculaPorcentagemVotoPostLoadProcessor implements IPostLoadProcessor {
	public void processSource(SessionConfig sessionConfig, Source source, Node parametersNode, ITransaction transaction)
			throws PortalException {
		TabularData tabularData = (TabularData) source.getData();
		for (ISourceData row : tabularData.getRows()) {
			Integer totalVotosCandidato = (Integer) row.get("totalVotosCandidato");
			Integer totalVotos = row.get("totalVotos", Integer.class);

			Double porcentagemVotos = 50.0;
			if (totalVotos != null && totalVotos.intValue() != 0)
				porcentagemVotos = Double.valueOf(totalVotosCandidato.doubleValue()
						/ totalVotos.doubleValue()) * 100;

			row.put("porcentagemVotos", porcentagemVotos);
		}
	}
}

O resultado é que campo declarado como externalData é exibido e mostra a porcentagem de votos de cada candidato:

image001.jpg

Seguindo uma linha semelhante, vamos ver agora como poderiamos adicionar novos registros ao source. Por quê isso seria necessário? Imagine que o seu source precise conter dados de uma base de dados da sua aplicação, e outra que você obtém de um outro sistema, por exemplo, através de uma chamada de Web Service. Você gostaria de unir os dados desses dois locais e exibir numa única interface. Uma opção seria a criação de um PostLoad Processor que buscasse os dados desse Web Service e adicionasse aos registros do seu source. Veja o exemplo:

package br.com.lumis.artigos.postload;
// imports omitidos
public class AdicionaCandidatoPostLoadProcessor implements IPostLoadProcessor {

	public void processSource(SessionConfig sessionConfig, Source source,
			Node parametersNode, ITransaction transaction)
			throws PortalException {
		TabularData tabularData = (TabularData) source.getData();
		List<String> candidatosSistemaExternos = getCandidatosSistemaExterno();
		
		for (String nomeCandidatoExterno : candidatosSistemaExternos) {
			ISourceData row = tabularData.addRow();
			row.put("NOME_CANDIDATO", nomeCandidatoExterno);
		}
	}
	
}
image002.jpg

3.Passando parâmetros para um PostLoad Processor

É possível passar parâmetros para os PostLoad Processors. Isso permite criar lógicas alternativas dentro do mesmo PostLoad Processor dependendo do valor do parâmetro passado. No início do artigo, mostramos um exemplo para exibir somente candidatos que tivessem destaque. Agora, imagine que gostariamos de alternar a exibição desses candidatos baseado no parâmetro que passasemos para o PostLoad Processor. Por exemplo, uma hora gostariamos de exibir candidatos com maior destaque, outra hora os de menor destaque. Poderiamos simplesmente adicionar esse parâmetro na chamada do PostLoad Processor:

<postLoadProcessors>
    <postLoadProcessor className="caminho.completo.da.classe">
	<parameters>
           <tipoCandidato>SEM_DESTAQUE</tipoCandidato>
        </parameters>
    </postLoadProcessor>
</postLoadProcessors>

E agora podemos obter o valor do parâmetro no PostLoad Processor da seguinte forma:

public void processSource(SessionConfig sessionConfig, Source source,
			Node parametersNode, ITransaction transaction)
			throws PortalException {
	
	String tipoCandidato = null;
        if (parametersNode != null) 
        	tipoCandidato = XmlUtil.readNodeString("tipoCandidato", parametersNode);

	if (tipoCandidato != null && tipoCandidato.equals("SEM_DESTAQUE")) {
		// lógica opcional	
	} else {
		// lógica opcional 2	
	}
}

4.Quando usar um PostLoad Processor?

De um modo geral, você pode utilizar um PostLoad Processor quando precisar adicionar, modificar ou remover dados do seu source original. Entretanto, verifique primeiro se algumas dessas operações não poderiam ser implementadas modificando diretamente a origem dos dados ou mesmo criando algum filtro customizado. Por exemplo, neste artigo foi mostrado a implementação de um PostLoad Processor para filtrar apenas candidatos em destaque. O mesmo filtro poderia ser feito utilizando um DataProvider customizado que aplicasse uma lógica semelhante. Nesse caso, você deve avaliar a solução que compensa mais, levando em consideração o tempo de desenvolvimento e a performance. Um exemplo de uma implementação que pode levar a problemas de performance, seria uma iteração em uma lista grande que faz diversas operações de banco de dados para cada registro.

Autor: Aman

Atualizado em 18.01.2011