RootManager editar arquivo

0:00 / 0:00

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().

CÓDIGO COMPLETO
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());
    }
}
RootManager (config)
0:00 / 0:00

public class RootManager extends JasapRootManager

ElementoO que significa
RootManagerExiste apenas uma instância desta classe no sistema. O Jasap a instancia automaticamente na inicialização do servidor (startup do Tomcat)
extends JasapRootManagerHerda do núcleo do Jasap. Cadeia completa: AppManagerJasapRootManagerRootManager

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 Exception

throws 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:

ActionO 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).

LinhaO 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.

RootManager (configGlobalFilters)
0:00 / 0:00

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 volta

Os 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âmetroValorO que é
domainDBtrueUsa 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_sgdbDataBase.POSTGRESTipo 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_port5432Porta 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

FiltroIda (request)Volta (response)
DataBaseFilterAbre o portão do estacionamento — abre a conexão com o banco via pool de conexões e disponibiliza para toda a cadeiaFecha o portão — commit() + closeConnection(). Está no finally: acontece sempre, mesmo se deu erro
PerfFilterO segurança que anota a hora que você entrou — registra data/hora, IP, memória do servidor, parâmetros da requisiçãoCalcula 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)
EffectFilterNa ida só observa, apenas repassaEmpacota 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
ErrorFilterO "plano B" — envolve o restante da cadeia em try/catchSe 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
PermissaoFilterCarrega 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 importa

Cada filtro depende do que o anterior já preparou:

Se mover...Problema
PerfFilter antes do DataBaseFilterdaoInsert() explode — não tem conexão aberta
AAFilter antes do DataBaseFilterNão consegue consultar o banco pra autenticar
PermissaoFilter antes do AAFilterTenta carregar permissões de um usuário que ainda não foi identificado
ErrorFilter depois do PermissaoFilterExceções na permissão não seriam logadas
EffectFilter depois do ErrorFilterErro técnico apareceria como stack trace cru em vez de mensagem amigável
DataBaseFilter no finalNingué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 locais

Os 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.

configGlobalFilters — Aprofundamento (cada filtro por dentro)
0:00 / 0:00

CallStack — como a cadeia funciona por dentro

O 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 dentro

O 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():

  • Se a action implementa NoDBAct — pula tudo (action que não precisa de banco, tipo servir arquivo estático)
  • Se a conexão ainda não existe — abre uma nova usando pool de conexões via JNDI + Apache DBCP2
  • Monta o nome do banco dinamicamente: "PRD_" + domínio do usuário — multi-tenant
  • Se dá erro na conexão — mostra alert ("Falha de Conexão")

Na 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 dentro

Ignora 3 tipos de requisição: NoDBAct (sem banco), isMultipart() (upload) e KeepAlive (ping). Para as demais, na ida registra:

CampoO que grava
nome_prfNome completo da classe (ex: br.xt.app.laboratorio.pessoa.LabPessoaList)
dt_ini_prfData/hora de entrada
ip_prfIP do usuário
totmen_prf / freemen_prfMemória total e livre da JVM
input_prfTodos 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 dentro

Este é 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:

  • Caminho feliz: result.execute(action) — serializa todos os eval() e update() em JSON para o browser
  • Caminho de erro: manager.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 logar

Divisão de responsabilidades: ErrorFilter loga (grava no banco) e EffectFilter mostra (troca stack trace por mensagem amigável).

AAFilter — por dentro

Na ida, 5 caminhos verificados nesta ordem:

#CondiçãoO que acontece
1Banco falhou (isFail())Redireciona pra página de login — não dá pra autenticar sem banco
2LogonInterfaceDeixa passar — é a tela de login, não precisa estar logado
3AnonymousActDeixa passar — action pública
4SESSION_USER na sessãoDeixa passar — já está logado. 99% das requisições caem aqui
5Nenhuma das anterioresTenta 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 dentro

Na ida: nada — só monta o try/catch. Na volta, se deu exceção:

Tipo de exceçãoNível do logO que é
JasapAlertExceptionlogAviso ("Alert")Erro esperado — validação, campo obrigatório, regra de negócio
Qualquer outralogFalha ("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 dentro

O 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 marcadoras

5 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".