Gerente geral do prédio — registra todos os managers de módulo e configura os filtros globais (portaria). O aluno adiciona uma única linha: new DepartamentoManager().config().
package br.xt;
import br.jasap.core.JasapRootManager;
import br.jasap.dao.DataBase;
import br.jasap.util.filters.EffectFilter;
import br.xt.app.painel.PnlManager;
import br.xt.acore.filters.AAFilter;
import br.xt.acore.filters.ErrorFilter;
import br.xt.acore.filters.PerfFilter;
import br.xt.acore.filters.PermissaoFilter;
import br.xt.acore.filters.DataBaseFilter;
import br.xt.app.ged.GedManager;
import br.xt.acore.desk.HomeManager;
import br.xt.app.laboratorio.LaboratorioManager;
import br.xt.app.departamento.DepartamentoManager;
public class RootManager extends JasapRootManager {
@Override
public void config() throws Exception {
regAction(AppsUpdateProgress.CheckProgress.class);
regAction(AppsUpdateProgress.StopProgress.class);
new PnlManager().config();
new HomeManager().config();
new GedManager().config();
new LaboratorioManager().config();
new DepartamentoManager().config();
}
@Override
public void sessionConfig() {
}
@Override
public void configGlobalFilters() throws Exception {
getGlobalFilters().add(
new DataBaseFilter(
true,
"BANCO_TREINAMENTO",
DataBase.POSTGRES,
"localhost",
5432,
"PRD_TREINAMENTO",
"postgres",
"1234"
)
);
getGlobalFilters().add(new PerfFilter());
getGlobalFilters().add(new EffectFilter());
getGlobalFilters().add(new AAFilter());
getGlobalFilters().add(new ErrorFilter());
getGlobalFilters().add(new PermissaoFilter());
}
}
public class RootManager extends JasapRootManager| Elemento | O que significa |
|---|---|
RootManager | Existe apenas uma instância desta classe no sistema. O Jasap a instancia automaticamente na inicialização do servidor (startup do Tomcat) |
extends JasapRootManager | Herda do núcleo do Jasap. Cadeia completa: AppManager → JasapRootManager → RootManager |
Do AppManager (o avô) herda: regAction(), config(), sessionConfig(), getSession(), getInput(), getOutput(), getDataBase(), invokeAction(). Do JasapRootManager (o pai direto) herda: getGlobalFilters() e o método abstrato configGlobalFilters(). O JasapRootManager é enxuto — só adiciona a responsabilidade dos filtros globais.
public void config() throws Exceptionthrows Exception significa que se algo der errado aqui, a exceção sobe direto para o Jasap → Tomcat. Não existe nenhum try/catch acima dele dentro do projeto — é o fim da linha. Se falhar, o deploy não sobe e o servidor não inicia. Por isso erros no config() são graves: não é um erro em tempo de execução que aparece pro usuário, é um erro que impede o sistema inteiro de funcionar.
regAction(AppsUpdateProgress.CheckProgress.class)
regAction(AppsUpdateProgress.StopProgress.class)Utilitário de barra de progresso para operações demoradas no servidor (atualizações de banco em lote, importações, relatórios pesados). Funciona como uma criança no banco de trás do carro:
| Action | O que faz |
|---|---|
CheckProgress | "Já chegou?" — o browser fica fazendo chamadas Ajax periódicas perguntando o percentual atual. O servidor responde ("falta 40%") e o browser desenha a barra de progresso na tela |
StopProgress | "Para o carro!" — permite cancelar a operação em andamento. O servidor interrompe a thread de processamento |
Estão registradas fora de qualquer módulo (direto no RootManager, antes dos managers) porque são transversais — qualquer módulo do sistema pode precisar mostrar uma barra de progresso.
new XxxManager().config()Aqui o gerente geral do prédio chega às 6h e entrega o crachá para cada gerente de departamento. Cada linha instancia um manager e chama o config() dele, que por sua vez registra todos os funcionários (regAction) e configura os crachás de acesso internos (regFun).
| Linha | O que registra |
|---|---|
new PnlManager().config() | Departamento de segurança — usuários, permissões, sessões. Deve ser o primeiro: ele fabrica os crachás de permissão que os outros departamentos dependem |
new HomeManager().config() | Recepção — tela inicial do sistema (desk) |
new GedManager().config() | Arquivo de documentos — gestão de documentos |
new LaboratorioManager().config() | Laboratório — módulo já existente no sistema |
new DepartamentoManager().config() | O novo departamento — única linha que o aluno adiciona ao criar um módulo |
sessionConfig()Corpo vazio neste projeto. Diferente do config() que roda uma vez no startup, o sessionConfig() roda toda vez que um usuário faz login (nova sessão HTTP). Serve para inicializar dados na sessão: preferências, cache, configurações padrão.
É como se o gerente geral tivesse um checklist para preencher cada vez que um funcionário bate o ponto de manhã. Neste prédio, o checklist existe mas está em branco — todo mundo entra e vai direto trabalhar.
O método não é abstrato — o AppManager já tem implementação vazia (public void sessionConfig(){}). O @Override aqui é tecnicamente redundante, mas deixa explícito que o método foi considerado. Em projetos reais seria usado para carregar preferências do usuário, cachear permissões ou configurar fuso horário.
O configGlobalFilters() configura a portaria do prédio — os guardas que todo mundo tem que passar antes de chegar ao departamento. Cada filtro é um "guarda" na entrada, em fila indiana.
Mecânica: ida e voltaOs filtros funcionam como uma boneca russa (matryoshka). Cada filtro envolve o próximo. Na ida (request chegando) passam na ordem 1→6 antes de chegar à action. Na volta (response saindo) passam em ordem inversa 6→1 após a action terminar.
Dentro de cada filtro, o ponto de divisão é o stack.next(manager): tudo antes dessa chamada é a ida, tudo depois é a volta.
1. DataBaseFilter → abre conexão
2. PerfFilter → anota hora de entrada
3. EffectFilter → (passa direto)
4. AAFilter → verifica autenticação
5. ErrorFilter → (monta try/catch)
6. PermissaoFilter → carrega permissões
ACTION.execute() ← o funcionário trabalha
6. PermissaoFilter → (nada)
5. ErrorFilter → loga erro se houver
4. AAFilter → (nada)
3. EffectFilter → empacota resposta / mostra erro amigável
2. PerfFilter → calcula tempo, mantém se >2s, deleta se <2s
1. DataBaseFilter → commit + fecha conexão
new DataBaseFilter(...)O primeiro filtro da cadeia — abre a conexão com o banco de dados. É o único filtro que recebe parâmetros no construtor — os outros 5 são new XxxFilter() sem parâmetros.
| Parâmetro | Valor | O que é |
|---|---|---|
| domainDB | true | Usa banco por domínio — monta o nome dinamicamente: "PRD_" + domínio. Permite multi-tenant (cada cliente com seu banco) |
| server_id | "BANCO_TREINAMENTO" | Identificador interno do pool de conexões — rótulo para gerenciar o pool |
| server_sgdb | DataBase.POSTGRES | Tipo do banco — constante numérica do Jasap que identifica PostgreSQL. Influencia como o SQL é gerado |
| server_host | "localhost" | Endereço do servidor de banco — máquina local. Em produção seria o IP do servidor dedicado |
| server_port | 5432 | Porta padrão do PostgreSQL |
| server_catalog | "PRD_TREINAMENTO" | Nome do banco de dados no PostgreSQL (o catalog) |
| server_user | "postgres" | Usuário de conexão com o banco |
| server_pass | "1234" | Senha do usuário de banco |
O construtor não abre conexão — só guarda os parâmetros em campos static. A conexão é aberta na ida do filter() e fechada na volta (finally: commit() + closeConnection()).
Os 6 filtros — o que cada um faz| Filtro | Ida (request) | Volta (response) |
|---|---|---|
DataBaseFilter | Abre o portão do estacionamento — abre a conexão com o banco via pool de conexões e disponibiliza para toda a cadeia | Fecha o portão — commit() + closeConnection(). Está no finally: acontece sempre, mesmo se deu erro |
PerfFilter | O segurança que anota a hora que você entrou — registra data/hora, IP, memória do servidor, parâmetros da requisição | Calcula quanto tempo ficou. Regra dos 2 segundos: se demorou mais de 2s, mantém o registro (requisição lenta, interessa investigar). Se demorou menos de 2s, deleta (não interessa) |
EffectFilter | Na ida só observa, apenas repassa | Empacota tudo que a action produziu — serializa todos os eval() e update() em JSON para o browser. Se deu erro: troca o stack trace por mensagem amigável (JasapAlertException → mensagem real; outra exceção → "Erro de execução, informe ao suporte") |
AAFilter | "Você tem crachá?" — verifica autenticação. 4 caminhos: banco falhou → login; LogonInterface → passa; AnonymousAct → passa; sessão ativa → passa; senão → tenta login com credenciais do input | — |
ErrorFilter | O "plano B" — envolve o restante da cadeia em try/catch | Se deu exceção, loga no banco via SlgModel (System Log): aviso para JasapAlertException, falha para erro técnico. Depois relança a exceção — quem mostra pro usuário é o EffectFilter acima |
PermissaoFilter | Carrega todas as permissões do usuário de uma vez na primeira requisição da sessão e marca uma flag. Nas próximas, a flag já existe e o filtro passa direto. Não bloqueia ninguém — quem bloqueia é o ok() dentro de cada action | — |
A ordem importaCada filtro depende do que o anterior já preparou:
| Se mover... | Problema |
|---|---|
| PerfFilter antes do DataBaseFilter | daoInsert() explode — não tem conexão aberta |
| AAFilter antes do DataBaseFilter | Não consegue consultar o banco pra autenticar |
| PermissaoFilter antes do AAFilter | Tenta carregar permissões de um usuário que ainda não foi identificado |
| ErrorFilter depois do PermissaoFilter | Exceções na permissão não seriam logadas |
| EffectFilter depois do ErrorFilter | Erro técnico apareceria como stack trace cru em vez de mensagem amigável |
| DataBaseFilter no final | Ninguém tem banco — tudo explode |
Na volta a ordem inversa também importa: o DataBaseFilter fecha a conexão por último, garantindo que o PerfFilter ainda tenha banco pra gravar o tempo de performance.
Filtros globais vs locaisOs 6 filtros do configGlobalFilters() são globais — rodam em toda requisição, sem exceção. Mas existem filtros locais que só rodam em actions específicas. O exemplo mais comum é o TransactionFilter:
public static class Insert extends LabPessoaAction {
public Insert() {
super.getFilters().add(new TransactionFilter());
}
}
O TransactionFilter só é adicionado em actions de escrita (Insert, Update, Delete). Actions de leitura (List, Sort) não precisam de transação.
A cadeia final fica: globais primeiro, locais depois. Para um Insert: DataBaseFilter → PerfFilter → EffectFilter → AAFilter → ErrorFilter → PermissaoFilter → TransactionFilter → action.execute().
Nenhum dos filtros globais precisa ser alterado ao criar um novo módulo — eles já cobrem o módulo novo automaticamente.
CallStack — como a cadeia funciona por dentroO CallStack mantém uma LinkedList com todos os filtros + a action no final. Quando uma requisição chega, o AppManager.invokeAction() monta o stack e chama stack.next(manager):
// AppManager.invokeAction()
setStack(new CallStack(action));
getStack().addFilters(action.getManager().getLocalFilters()); // globais
getStack().addFilters(action.getFilters()); // locais
Effect effect = getStack().next(this);
Cada chamada a stack.next() remove o primeiro filtro da lista e chama o filter() dele. Dentro do filter(), o filtro faz seu trabalho de ida, depois chama stack.next() de novo — que remove o próximo, e assim por diante. Quando a lista fica vazia, o CallStack chama action.execute(). O resultado volta pela pilha de chamadas recursivas.
DataBaseFilter — por dentroO construtor guarda os 8 parâmetros de conexão em campos public static — qualquer parte do sistema pode acessar DataBaseFilter.SERVERDB_HOST etc. Também chama DataBase.setSGDB() que configura globalmente qual SGBD o Jasap usa.
Na ida do filter():
NoDBAct — pula tudo (action que não precisa de banco, tipo servir arquivo estático)"PRD_" + domínio do usuário — multi-tenantNa volta (finally): commit(true) + closeConnection(true). Está no finally — acontece sempre, mesmo se deu exceção. É a garantia de que a conexão nunca fica "presa".
PerfFilter — por dentroIgnora 3 tipos de requisição: NoDBAct (sem banco), isMultipart() (upload) e KeepAlive (ping). Para as demais, na ida registra:
| Campo | O que grava |
|---|---|
nome_prf | Nome completo da classe (ex: br.xt.app.laboratorio.pessoa.LabPessoaList) |
dt_ini_prf | Data/hora de entrada |
ip_prf | IP do usuário |
totmen_prf / freemen_prf | Memória total e livre da JVM |
input_prf | Todos os parâmetros da requisição |
Na volta calcula o tempo total e aplica a regra dos 2 segundos: demorou mais de 2s → daoUpdate() (mantém pra análise); demorou menos → daoDelete() (descarta). A tabela de performance só acumula requisições lentas.
EffectFilter — por dentroEste é do Jasap (br.jasap.util.filters), não do projeto. Estende Filter direto (não RootFilter) — não tem acesso a getFactory().
Na ida: nada. Na volta, dois caminhos:
result.execute(action) — serializa todos os eval() e update() em JSON para o browsermanager.getOutput().reset() (limpa output parcial), depois mostra mensagem amigável. JasapAlertException → mostra a mensagem real. Outra exceção → "Erro de execução, informe ao suporte". Depois faz throw e — relança pro ErrorFilter logarDivisão de responsabilidades: ErrorFilter loga (grava no banco) e EffectFilter mostra (troca stack trace por mensagem amigável).
AAFilter — por dentroNa ida, 5 caminhos verificados nesta ordem:
| # | Condição | O que acontece |
|---|---|---|
| 1 | Banco falhou (isFail()) | Redireciona pra página de login — não dá pra autenticar sem banco |
| 2 | LogonInterface | Deixa passar — é a tela de login, não precisa estar logado |
| 3 | AnonymousAct | Deixa passar — action pública |
| 4 | SESSION_USER na sessão | Deixa passar — já está logado. 99% das requisições caem aqui |
| 5 | Nenhuma das anteriores | Tenta autenticar com login/senha do input (AALocal) |
O AALocal trata o formato usuario@DOMINIO, autentica no banco, verifica se está inativo, e se der certo: grava cookies (login + domínio), coloca o PusuBean na sessão, registra IP e data, e redireciona pro WorkSpace.jsap. Se der exceção, destrói a sessão por segurança (session.invalidate()).
ErrorFilter — por dentroNa ida: nada — só monta o try/catch. Na volta, se deu exceção:
| Tipo de exceção | Nível do log | O que é |
|---|---|---|
JasapAlertException | logAviso ("Alert") | Erro esperado — validação, campo obrigatório, regra de negócio |
| Qualquer outra | logFalha ("Jasap") + printStackTrace() | Erro técnico — NullPointer, SQL, bug |
Nos dois casos: captura o stack trace completo, grava no banco via SlgModel (System Log), e relança a exceção (throw e). O ErrorFilter não engole o erro — só loga e repassa.
PermissaoFilter — por dentroO mais enxuto de todos. Na ida: se a action não é AnonymousAct e a flag PERMISSAO_SESSION ainda não existe na sessão, chama daoCarregarPermissoes() — carrega todas as permissões do usuário de uma vez do banco e marca a flag. Na segunda requisição em diante, a flag já existe e o filtro passa direto.
Não bloqueia ninguém. Só carrega. Quem bloqueia é o ok("chave") dentro de cada action/form que consulta o cache na sessão.
Eficiência: carregar tudo de uma vez evita N queries por tela. Uma tela com 10 botões verificando permissão faz 0 queries — só leitura de memória. A desvantagem: se o admin mudar permissões de um usuário logado, o usuário precisa relogar pra pegar as novas permissões.
RootFilter e interfaces marcadoras5 dos 6 filtros estendem RootFilter (não Filter direto). O RootFilter adiciona uma única coisa: getFactory() — acesso à ferramentaria central. O EffectFilter é a exceção: vem do Jasap e estende Filter direto.
NoDBAct e AnonymousAct são interfaces marcadoras (marker interfaces). Não têm nenhum método — a action só implementa (implements NoDBAct) e os filtros reconhecem via instanceof. É como pendurar uma placa na porta: "não preciso de banco" ou "sou público".