O Manager no Jasap não é uma pessoa — é a infraestrutura que monta e acompanha cada requisição. RootManager, ModuloManager e AppManager são nomes de níveis, não entidades separadas. Na hora da requisição, existe um único objeto manager do início ao fim.
No projeto de estudo, a cadeia completa é:
AppManager (Jasap — base abstrata)
└── JasapRootManager (Jasap — configuração de filtros globais)
└── RootManager (br.xt — registra módulos)
└── PnlManager (br.xt.app.painel — painel de controle)
└── DepartamentoManager (br.xt.app.departamento — seu módulo)
Cada classe herda tudo da anterior. Quando o Jasap cria um new DepartamentoManager(), esse objeto já é um PnlManager, já é um RootManager, já é um AppManager — tudo junto numa instância só.
Os nomes diferentes existem pelo mesmo motivo que endereço tem País, Estado e Rua — são níveis de organização do mesmo ponto:
| Nível | Classe | O que configura |
|---|---|---|
| Raiz | RootManager | Filtros globais (DataBaseFilter, AAFilter...), registra os módulos |
| Módulo | PnlManager / DepartamentoManager | Actions e permissões do módulo, filtros adicionais |
| App/CRUD | AppManager (menor nível) | Actions do CRUD específico — não registra outros managers |
O Manager aparece em dois momentos da vida do sistema, com papéis diferentes em cada um:
Quando o Tomcat inicia, o RootManager.config() é chamado uma única vez. Ele cria instâncias temporárias de cada ModuloManager só para registrar as actions:
// RootManager.config() — roda UMA VEZ na inicialização
public void config() throws Exception {
new PnlManager().config(); // instância temporária
new DepartamentoManager().config(); // instância temporária — registra e descarta
}
Cada config() chama regAction(), que grava num XML global: "esta action pertence a este manager".
<!-- Mapa gerado pelo regAction — fica na memória do servidor -->
<url action="br.xt.app.departamento.DepartamentoHome"
manager="br.xt.app.departamento.DepartamentoManager"/>
Depois que o config() termina, essas instâncias temporárias são descartadas. Serviram apenas para montar o mapa.
Quando uma requisição chega, o JasapController.service() faz o trabalho real:
// JasapController.service() — roda A CADA REQUISIÇÃO
public void service(HttpServletRequest request, HttpServletResponse response) {
// 1. Consulta o XML: qual manager registrou essa action?
Element eURL = mapURL.getElementById(actionURL);
String clsManager = eURL.getAttribute("manager"); // "DepartamentoManager"
String clsAction = eURL.getAttribute("action"); // "DepartamentoHome"
// 2. Cria UMA instância nova do manager certo
AppManager manager = Class.forName(clsManager).newInstance();
// 3. Importa os filtros globais do RootManager
manager.importGlobalFilters(rootManager.getGlobalFilters());
// 4. Configura o manager com o contexto da requisição
manager.setInput(new Input(request));
manager.setOutput(new Output(response));
manager.setSession(new Session(request.getSession()));
// 5. Cria a action e conecta ao manager
JasapAct action = Class.forName(clsAction).newInstance();
action.setManager(manager); // O BINDING — action e manager conectados
// 6. Executa
manager.invokeAction(action);
}
| Passo | O que acontece |
|---|---|
| 1. Consulta | O Jasap olha o mapa XML e descobre: "essa URL foi registrada pelo DepartamentoManager" |
| 2. Instância | Cria um new DepartamentoManager() — que por herança já é PnlManager + AppManager |
| 3. Filtros | Copia os filtros globais (DataBaseFilter, AAFilter...) para este manager |
| 4. Contexto | Injeta request, response e session — agora o manager conhece o usuário e pode responder |
| 5. Binding | Cria a action e conecta ao manager — a partir daqui, action.getManager() retorna este manager |
| 6. Execução | O manager executa os filtros na ordem e depois chama action.execute() |
Porque são níveis de organização, não entidades separadas.
Se todo o código de configuração ficasse num arquivo só — filtros globais, permissões de todos os módulos, actions de todos os CRUDs — funcionaria. Mas seria um arquivo com milhares de linhas, impossível de manter.
A separação em níveis permite:
| Benefício | Como funciona |
|---|---|
| Modularidade | Cada módulo tem seu próprio Manager com suas actions — adicionar ou remover um módulo é mexer em um arquivo |
| Escopo claro | Filtros globais ficam no Root, permissões do módulo ficam no Módulo — cada coisa no seu lugar |
| Herança Java | O DepartamentoManager herda regAction() e regFun() sem reimplementar nada |
Na requisição, a herança garante que a instância criada tem tudo:
DepartamentoManager manager = new DepartamentoManager();
// manager É um PnlManager → tem regFun(), mapFUN
// manager É um AppManager → tem regAction(), setInput(), setOutput()
// manager É um RootManager → tem configGlobalFilters()
// Tudo numa instância só — a herança Java faz o merge automaticamente
Quando DepartamentoManager.config() chama regAction(DepartamentoHome.class), o que acontece internamente é:
// AppManager.mapURL() — dentro do regAction
public void mapURL(String call, Class actionClass) throws Exception {
Element url = JasapController.mapURL.newElement("url");
url.setAttribute("id", call); // URL hasheada
url.setAttribute("action", actionClass.getName()); // "br.xt...DepartamentoHome"
url.setAttribute("manager", this.getClass().getName()); // "br.xt...DepartamentoManager"
JasapController.mapURL.getRootElement().appendChild(url);
}
O ponto chave é o this.getClass().getName() — o método grava qual manager está chamando. Como quem chama é o DepartamentoManager, fica registrado "br.xt.app.departamento.DepartamentoManager".
Depois, na requisição, o JasapController lê esse atributo e sabe exatamente qual classe instanciar com Class.forName().
USUÁRIO clica em "Departamento" no menu
↓
BROWSER envia requisição HTTP para "a1b2c3d4.jsap"
↓
JASAPCONTROLLER.service()
↓
CONSULTA mapURL → action: DepartamentoHome, manager: DepartamentoManager
↓
NEW DepartamentoManager() — instância com tudo herdado
↓
importGlobalFilters() — copia DataBaseFilter, AAFilter, etc.
↓
setInput(request), setOutput(response), setSession(session)
↓
NEW DepartamentoHome() — action criada
↓
action.setManager(manager) — BINDING
↓
manager.invokeAction(action)
↓
FILTROS executam na ordem → action.execute() → monta a tela
↓
RESPONSE enviada ao browser