🎮 Services (Controllers)

⚠️

Acesso Antecipado (Beta)

Esta documentação refere-se a uma versão em acesso antecipado do SDK Sankhya. As funcionalidades e APIs estão sujeitas a modificações. Para obter acesso, envie um e-mail para [email protected] informando a appkey do seu projeto.

🎮 Camada de Serviço (@Service)

No SDK Sankhya, a anotação @Service transforma uma classe Java em um endpoint para requisições externas, funcionando como um Controller no padrão MVC. Ela orquestra a interação entre o mundo exterior e a lógica de negócio da aplicação.

Por que usar @Service?

  • Clareza Arquitetural: Separa a camada de apresentação da lógica de negócio.
  • Padrão de Mercado: Alinhado com frameworks como Spring.
  • Integração Total: Suporte a injeção de dependências, validação e controle transacional.
  • Separação de Responsabilidades: O serviço recebe, valida e delega requisições, sem executar regras de negócio complexas.

Abordagem Antiga vs. Nova

A abordagem antiga exigia a manipulação manual de ServiceContext, resultando em um código verboso, acoplado e difícil de testar.

❌ Abordagem Tradicional (ServiceBean)

// Código legado: verboso, acoplado e difícil de testar
/**
 * @ejb.bean name="PedidoServiceSP"
 * jndi-name="mge/placemm/ejb/session/PedidoServiceSP"
 * type="Stateless" transaction-type="Container" view-type="remote"
 * @ejb.transaction type="Supports"
 * @ejb.util generate="false"
 */
public class PedidoServiceSPBean extends ServiceBean {
    public void criarPedido(ServiceContext sctx) throws Exception {
        JapeSession.SessionHandle hnd = null;
        try {
            hnd = JapeSession.open();

              // Lógica manual de transação, parsing de JSON, etc.
            JsonObject json = (JsonObject) sctx.getJsonRequestBody();
            // ... muito código boilerplate ...
        } finally {
            JapeSession.close(hnd);
        }
    }
}

✅ Nova Abordagem com @Service

A nova abordagem é declarativa, limpa e integrada com os demais pilares do SDK.

@Service(serviceName = "PedidoServiceSP")
public class PedidoService {
    private final PedidoBusinessService businessService;

    @Inject
    public PedidoService(PedidoBusinessService businessService) {
        this.businessService = businessService;
    }

    @Transactional // O SDK gerencia a transação
    public void criarPedido(@Valid PedidoDTO pedido) {
        // 1. @Valid: Validação automática do DTO
        // 2. Delegação para a camada de negócio
        businessService.criar(pedido);
        
    }
}

Como funciona o @Service

  • Atributo obrigatórioserviceName: Define o nome do serviço registrado na plataforma (por convenção, termina com SP).
  • Métodos públicos: Tornam-se "ações" do serviço, acessíveis externamente.
  • Injeção de dependências: Via construtor.

URL de acesso:
.../service.sbr?serviceName=<nomeDoServico>.<nomeDoMetodo>

Exemplo:
.../mge/service.sbr?serviceName=PedidoServiceSP.criarPedido


Controle Transacional (transactionType)

A anotação @Service permite configurar o comportamento transacional padrão para todos os métodos da classe através do atributo transactionType:

@Service(
    serviceName = "RelatorioServiceSP",
    transactionType = TransactionType.NotSupported
)
public class RelatorioService {
    // ...
}
TransactionTypeDescriçãoQuando Usar
RequiredGarante que o método sempre execute dentro de uma transação. Se já existir, utiliza-a; senão, cria uma nova.Ideal para operações de escrita (CRUD).
NotSupportedExecuta fora de qualquer transação. Se houver uma ativa, ela é suspensa.Operações de leitura que não precisam de consistência transacional.
SupportedExecuta dentro de uma transação se já houver uma ativa; caso contrário, executa sem transação.Operações de leitura que podem ou não fazer parte de uma transação maior. (Padrão)

Nota: A anotação @Transactional em um método sempre tem precedência sobre o transactionType definido na classe, permitindo controle granular.

Sobrepondo o padrão com @Transactional

@Service(serviceName = "ConsultaServiceSP", transactionType = TransactionType.NotSupported)
public class ConsultaService {
    
    // Este método usa o padrão da classe (NotSupported)
    public List<ProdutoDTO> listarProdutos() {
        // ... lógica de consulta ...
    }

    @Transactional(type = TransactionType.RequiresNew) // Sobrepõe o padrão
    public void registrarLogDeConsulta() {
        // Executa em sua própria transação
    }
}

Boas Práticas

  1. Mantenha Controllers "Magros": O @Service deve apenas receber a requisição, validar (@Valid) e delegar para um componente de negócio. Não coloque regras de negócio complexas no Controller.

    @Service(serviceName = "UsuarioServiceSP")
    public class UsuarioController {
        private final UsuarioService usuarioService;
    
        @Inject
        public UsuarioController(UsuarioService usuarioService) {
            this.usuarioService = usuarioService;
        }
    
        @Transactional
        public void ativarUsuario(Long usuarioId) {
            usuarioService.ativar(usuarioId);
        }
    }
  2. Use DTOs: Sempre utilize Data Transfer Objects para entrada e saída, desacoplando a camada de serviço da persistência e evitando exposição de dados sensíveis.

  3. Injeção via construtor: Prefira sempre a injeção de dependências via construtor para facilitar testes e explicitar dependências.

  4. Serviços de leitura: Para serviços apenas de consulta, use transactionType = TransactionType.NotSupported para otimizar desempenho.

  5. Valide entradas: Use @Valid nos DTOs para garantir dados corretos antes do processamento.


A anotação @Service é a peça central que conecta seu Add-on ao ecossistema Sankhya, permitindo a criação de serviços robustos, testáveis e alinhados com as melhores práticas do mercado.