Usando a máquina de estado Spring no exemplo do protocolo ROSEU
O artigo descreve o uso da máquina de estado Spring usando um exemplo de estabelecimento de uma conexão de acordo com a tecnologia ROSEU. É estabelecida uma conexão entre dois operadores EDO no modo ponto a ponto ou através de um centro de roaming. Ele descreve como gerenciar estados, alternar estados por evento e executar ações especificadas ao alterar estados. Se estiver interessado, peço um gato.

O protocolo ROSEU é descrito em detalhes
aqui .
Para um artigo, precisamos apenas conhecer o princípio de estabelecer uma conexão entre dois clientes EDI. Cada um deles envia um convite para estabelecer uma conexão. O tipo de convite é "Solicitação" ou "Interrupção".
Para estabelecer uma conexão, os dois participantes do fluxo de trabalho devem enviar um convite do tipo "Solicitação". Depois disso, a conexão é considerada estabelecida.
Se um dos participantes enviar um convite do tipo "Interromper", a conexão será desconectada.
Em nosso sistema, estabelecemos sete status possíveis para os participantes do EDI.
- Falha na conexão - NO_CONNECTION
- Nosso cliente enviou um convite para roaming. Mas ainda não o entregamos. É justificado pela assincronia da instituição do pedido e pelo seu envio ao centro de roaming. - INVITATION_SAVED
- Conexão estabelecida com sucesso - ARE_CONNECTED
- Conexão encerrada por iniciativa de um dos participantes - CONNECTION_BROKEN
- Recebeu um convite externo, nosso cliente não enviou nada antes - INVITATION_RECEIVED
- Convite do nosso cliente aceito pelo centro de roaming - INVITATION_SEND
- Erro de conexão - CONNECTION_ERROR
Eventos possíveis:
- Nosso cliente enviou um convite para "Solicitar". - OUTCOME_INVITATION
- Nosso cliente enviou um convite "Break" - OUTCOME_REJECT
- Um cliente externo enviou um convite de "Solicitação" - INCOME_INVITATION
- O cliente externo enviou um convite para "Intervalo" - INCOME_REJECT
- Roaming Center aceitou o convite com sucesso - RC_SUCCESS
- O centro de roaming não aceitou o convite - RC_ERROR
Tabela de mudança de status. A primeira linha é o status inicial. A primeira coluna é um evento. No cruzamento - um novo status.

Essa mudança de status pode ser codificada através da opção if-if-else. Mas através da máquina de estado, na minha opinião, isso será mais conveniente.
A lógica é a seguinte - se alguém for desconectado, qualquer pessoa poderá restabelecê-la. Se ocorreu um erro ao estabelecer uma conexão, nada mais pode ser feito; a solução de problemas manual é necessária.
A documentação detalhada sobre a máquina do estado Spring foi retirada
daqui .
Vamos criar o carro através do construtor
StateMachineBuilder.Builder<ClientsState, ContractorEvent> builder = StateMachineBuilder.builder();
Em seguida, definimos todos os status possíveis. O status inicial é definido como o status atual dos clientes.
builder.configureStates() .withStates() .initial(initialState) .states(EnumSet.allOf(ClientsState.class));
Nós configuramos a inicialização automática do carro. Caso contrário, você terá que iniciar manualmente
builder.configureConfiguration() .withConfiguration() .autoStartup(true);
Em seguida, prescrevemos tranches.
origem - status inicial,
destino - status final,
evento - evento no qual a troca de status ocorre,
ação - atualiza os status do cliente.
builder.configureTransitions() .withExternal() .source(NO_CONNECTION) .target(INVITATION_RECEIVED) .event(INCOME_INVITATION) .action(updateStateAction) .and() .withExternal() .source(NO_CONNECTION) .target(CONNECTION_BROKEN) .event(INCOME_REJECT) .action(updateStateAction)
Depois de criar a máquina de estado, passamos o
evento para sua entrada. Mas, em
ação, precisamos de informações adicionais para atualizar o status dos clientes. Portanto, envolvemos o
evento na
mensagem e colocamos os dados necessários no
cabeçalho .
StateMachine<ClientsState, ContractorEvent> sm = builder.build(); Map<String, Object> clients = new HashMap<>(); clients.put("client1", "client11"); clients.put("client2", "client22"); MessageHeaders headers = new MessageHeaders(clients); Message<ContractorEvent> message = new GenericMessage<>(event, headers); sm.sendEvent(message); sm.stop();
Além disso
, esses dados são extraídos e usados.
@Service public class UpdateStateAction implements Action<ClientsState, ContractorEvent> { @Override public void execute(StateContext<ClientsState, ContractorEvent> context) { System.out.println("Source state: " + context.getSource()); System.out.println("Target state: " + context.getTarget()); System.out.println("Event: " + context.getEvent()); MessageHeaders headers = context.getMessageHeaders(); System.out.println(headers.get("client1")); System.out.println(headers.get("client2")); } }
Você também pode usar a
proteção para impedir alterações de status, mas, no nosso caso, isso não é necessário.
É basicamente isso. O código fonte do exemplo pode ser obtido no
link .
No artigo, examinamos como usar a máquina de estado Spring para codificar a tabela de transição de estado.
Este não é todos os seus recursos, mas apenas o mais básico. Espero que o artigo tenha sido útil e incentive você a usar essa estrutura.
Se você tem experiência pessoal em usá-lo, faça o comentário.
UPD
Durante o uso, um recurso interessante foi revelado - no caso de uma exceção em uma das ações padrão, o erro não é gerado, mas simplesmente registrado. Nesse caso, a execução de toda a máquina de estado não para. E mesmo o método hasStateMachineError retorna false.
Como decisão, fizemos uma AbstractAction na qual capturamos a exceção e a colocamos no contexto da máquina de estado. Depois disso, no caso de uma exceção, hasStateMachineError retorna true e, em seguida, processamos mais.
@Override public void execute(StateContext<StatesEnum, OperationsEnum> context) { try { prepareContext(context); executeInternal(context); } catch (Exception e) { logger.error(" state machine", e); context.getStateMachine().setStateMachineError(e); } }