RegistrationServiceImpl.java
/*
* Copyright 2005-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.openwms.wms.registration.impl;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull;
import org.ameba.annotation.Measured;
import org.ameba.annotation.TxService;
import org.openwms.core.listener.RemovalNotAllowedException;
import org.openwms.wms.registration.RegistrationService;
import org.openwms.wms.registration.events.DeletionFailedEvent;
import org.openwms.wms.registration.events.EntityType;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.web.client.RestTemplate;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import static java.lang.String.format;
/**
* A RegistrationServiceImpl.
*
* @author Heiko Scherrer
*/
@TxService
class RegistrationServiceImpl implements RegistrationService {
private static final Logger LOGGER = LoggerFactory.getLogger(RegistrationServiceImpl.class);
private final ApplicationEventPublisher eventPublisher;
private final RestTemplate aLoadBalanced;
private final ReplicaRegistryRepository repository;
RegistrationServiceImpl(ApplicationEventPublisher eventPublisher, RestTemplate aLoadBalanced, ReplicaRegistryRepository repository) {
this.eventPublisher = eventPublisher;
this.aLoadBalanced = aLoadBalanced;
this.repository = repository;
}
/**
* {@inheritDoc}
*/
@Override
@Measured
public boolean registrarsExist(@NotNull EntityType entityName) {
return repository.existActiveOnes(entityName);
}
/**
* {@inheritDoc}
*/
@Override
@Measured
public void remove(@NotNull EntityType entityName, @NotBlank String pKey) {
var registeredServices = repository.findActiveOnes(entityName);
if (registeredServices.isEmpty()) {
LOGGER.info("No registrars for entity [{}] registered, so removal is allowed", entityName);
return;
}
try {
// first ask all services and call the requestRemovalEndpoint
// might throw RemovalNotAllowedException and exit
for (var srv : registeredServices) {
askForRemoval(srv, List.of(pKey));
}
// if all are fine then call the removeEndpoint to mark the entity as deleted and not be visible in the foreign service
for (var srv : registeredServices) {
remove(srv, List.of(pKey));
}
} catch (Exception e) {
LOGGER.error(e.getMessage(), e);
// if any failure occurs, send a persistent async message to release the deletion for everyone
eventPublisher.publishEvent(new DeletionFailedEvent(pKey, "product.event.deletion-rollback", EntityType.PRODUCT));
throw new RemovalNotAllowedException(e.getMessage());
}
}
private void askForRemoval(ReplicaRegistry srv, Collection<String> pKeys) {
var headers = new HttpHeaders();
boolean result;
var endpoint = "http://" + srv.getApplicationName() + srv.getRequestRemovalEndpoint();
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("Request for removal to the service with API [{}]", endpoint);
}
try {
var response = aLoadBalanced.exchange(
endpoint,
HttpMethod.POST,
new HttpEntity<List<String>>(new ArrayList<>(pKeys), headers),
Boolean.class
);
result = response.getBody() != null && response.getBody();
if (result) {
LOGGER.info("Service [{}] allows to remove all entities", srv.getApplicationName());
} else {
LOGGER.info("Service [{}] does not allow to remove entities", srv.getApplicationName());
}
} catch (Exception e) {
LOGGER.error(e.getMessage(), e);
throw new RemovalNotAllowedException("Exception. Removal of entities is declined by service [%s]".formatted(srv.getApplicationName()));
}
if (!result) {
throw new RemovalNotAllowedException("Removal of entities has been declined by service [%s]".formatted(srv.getApplicationName()));
}
}
private void remove(ReplicaRegistry srv, Collection<String> pKeys) {
var headers = new HttpHeaders();
var endpoint = "http://" + srv.getApplicationName() + srv.getRemovalEndpoint();
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("Ask for removal the service with API [{}]", endpoint);
}
try {
aLoadBalanced.exchange(
endpoint,
HttpMethod.DELETE,
new HttpEntity<List<String>>(new ArrayList<>(pKeys), headers),
Void.class
);
LOGGER.info("Service [{}] removed entities", srv.getApplicationName());
} catch (Exception e) {
throw new RemovalNotAllowedException(format("Exception. Removal of entities is declined by service [%s]", srv.getApplicationName()));
}
}
}