diff --git a/src/ztp/src/main/java/org/etsi/tfs/ztp/ZtpServiceImpl.java b/src/ztp/src/main/java/org/etsi/tfs/ztp/ZtpServiceImpl.java index 0f0f502d5a8c8baa1de9f12020f570c0b01d2f11..953d84aa3f556b2f48557351ba7d2cc3286a09e1 100644 --- a/src/ztp/src/main/java/org/etsi/tfs/ztp/ZtpServiceImpl.java +++ b/src/ztp/src/main/java/org/etsi/tfs/ztp/ZtpServiceImpl.java @@ -23,12 +23,12 @@ import org.etsi.tfs.ztp.context.ContextService; import org.etsi.tfs.ztp.context.model.Device; import org.etsi.tfs.ztp.context.model.DeviceConfig; import org.etsi.tfs.ztp.device.DeviceService; +import org.etsi.tfs.ztp.exception.ExternalServiceFailureException; import org.jboss.logging.Logger; @ApplicationScoped public class ZtpServiceImpl implements ZtpService { private static final Logger LOGGER = Logger.getLogger(ZtpServiceImpl.class); - // private static final String MESSAGE = "Retrieved %s"; private final DeviceService deviceService; private final ContextService contextService; @@ -41,128 +41,104 @@ public class ZtpServiceImpl implements ZtpService { @Override public Uni<Device> addDevice(String deviceId) { - final var deserializedDeviceUni = contextService.getDevice(deviceId); - - deserializedDeviceUni + return contextService + .getDevice(deviceId) .onFailure() - .recoverWithNull() - .subscribe() - .with( + .transform(failure -> new ExternalServiceFailureException(failure.getMessage())) + .onItem() + .transformToUni( device -> { - final var id = deviceId; - - if (device == null) { - LOGGER.warnf("%s is null. Ignoring...", device); - return; - } - if (device.isEnabled()) { LOGGER.warnf("%s has already been enabled. Ignoring...", device); - return; + return Uni.createFrom().failure(new Exception("Device is already enabled")); + } else { + return addDeviceTo(device, deviceId); } + }); + } - // LOGGER.infof(MESSAGE, device); - - final var initialConfiguration = - deviceService.getInitialConfiguration(device.getDeviceId()); - - device.enableDevice(); - LOGGER.infof("Enabled device [%s]", id); + public Uni<Device> addDeviceTo(Device device, String deviceId) { + LOGGER.infof("Enabling device with ID [%s]", deviceId); + device.enableDevice(); - initialConfiguration - .subscribe() - .with( - deviceConfig -> { - device.setDeviceConfiguration(deviceConfig); - final var configuredDeviceIdUni = deviceService.configureDevice(device); + final Uni<DeviceConfig> initialConfiguration = deviceService.getInitialConfiguration(deviceId); - configuredDeviceIdUni - .subscribe() - .with( - configuredDeviceId -> - LOGGER.infof( - "Device [%s] has been successfully enabled and configured with %s.\n", - id, deviceConfig)); + return initialConfiguration + .onItem() + .transformToUni( + deviceConfig -> { + device.setDeviceConfiguration(deviceConfig); + LOGGER.infof( + "Configuring device with ID [%s] with initial configuration %s", + deviceId, deviceConfig); + return deviceService + .configureDevice(device) + .map( + configuredDeviceId -> { + LOGGER.infof( + "Device with ID [%s] has been successfully enabled and configured.", + deviceId); + return device; }); }); - - return deserializedDeviceUni; } @Override public Uni<Device> deleteDevice(String deviceId) { - final var deserializedDeviceUni = contextService.getDevice(deviceId); - - deserializedDeviceUni + return contextService + .getDevice(deviceId) .onFailure() - .recoverWithNull() - .subscribe() - .with( + .transform(failure -> new ExternalServiceFailureException(failure.getMessage())) + .onItem() + .transformToUni( device -> { - final var id = deviceId; - - if (device == null) { - LOGGER.warnf("%s is null. Ignoring...", device); - return; - } - if (device.isDisabled()) { - LOGGER.warnf("%s has already been disabled. Ignoring...", device); - return; + LOGGER.warnf("Device with ID %s has already been disabled. Ignoring...", deviceId); + return Uni.createFrom().nullItem(); + } else { + LOGGER.infof("Disabling device with ID [%s]", deviceId); + device.disableDevice(); + + return deviceService + .deleteDevice(deviceId) + .onItem() + .transform( + emptyMessage -> { + LOGGER.infof( + "Device with ID [%s] has been successfully deleted.", deviceId); + return device; + }); } - - device.disableDevice(); - LOGGER.infof("Disabled device [%s]", id); - - // LOGGER.infof(MESSAGE, device); - - final var empty = deviceService.deleteDevice(device.getDeviceId()); - - empty - .subscribe() - .with( - emptyMessage -> - LOGGER.infof("Device [%s] has been successfully deleted.\n", id)); }); - - return deserializedDeviceUni; } @Override public Uni<Device> updateDevice(String deviceId, DeviceConfig deviceConfig) { - final var deserializedDeviceUni = contextService.getDevice(deviceId); - - deserializedDeviceUni + return contextService + .getDevice(deviceId) .onFailure() - .recoverWithNull() - .subscribe() - .with( + .transform(failure -> new ExternalServiceFailureException(failure.getMessage())) + .onItem() + .transformToUni( device -> { - final var id = deviceId; - - if (device == null) { - LOGGER.warnf("%s is null. Ignoring...", device); - return; - } - if (!device.isEnabled()) { - LOGGER.warnf("Cannot update disabled device %s. Ignoring...", device); - return; - } - - // LOGGER.infof(MESSAGE, device); - device.setDeviceConfiguration(deviceConfig); - final var updatedDeviceIdUni = deviceService.configureDevice(device); - - updatedDeviceIdUni - .subscribe() - .with( - configuredDeviceId -> + LOGGER.warnf("Cannot update disabled device %s. Ignoring...", deviceId); + return Uni.createFrom().nullItem(); + } else { + LOGGER.infof("Updating configuration of device with ID [%s]", deviceId); + device.setDeviceConfiguration(deviceConfig); + + return deviceService + .configureDevice(device) + .onItem() + .transform( + configuredDeviceId -> { LOGGER.infof( - "Device [%s] has been successfully updated with %s.\n", - id, deviceConfig)); + "Device with ID [%s] has been successfully updated with %s.", + deviceId, deviceConfig); + return device; + }); + } }); - - return deserializedDeviceUni; } } diff --git a/src/ztp/src/main/java/org/etsi/tfs/ztp/exception/ExternalServiceFailureException.java b/src/ztp/src/main/java/org/etsi/tfs/ztp/exception/ExternalServiceFailureException.java new file mode 100644 index 0000000000000000000000000000000000000000..fe25f18c371b8d8176eecadda101058e0df6e284 --- /dev/null +++ b/src/ztp/src/main/java/org/etsi/tfs/ztp/exception/ExternalServiceFailureException.java @@ -0,0 +1,28 @@ +/* +* Copyright 2022-2023 ETSI TeraFlowSDN - TFS OSG (https://tfs.etsi.org/) +* +* 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.etsi.tfs.ztp.exception; + +public class ExternalServiceFailureException extends RuntimeException { + + public ExternalServiceFailureException(String message, Exception e) { + super(message, e); + } + + public ExternalServiceFailureException(String message) { + super(message); + } +} diff --git a/src/ztp/src/main/java/org/etsi/tfs/ztp/exception/GeneralExceptionHandler.java b/src/ztp/src/main/java/org/etsi/tfs/ztp/exception/GeneralExceptionHandler.java new file mode 100644 index 0000000000000000000000000000000000000000..45886e97531f2b8c89c4b32ee8f950a11d1a16ea --- /dev/null +++ b/src/ztp/src/main/java/org/etsi/tfs/ztp/exception/GeneralExceptionHandler.java @@ -0,0 +1,57 @@ +/* +* Copyright 2022-2023 ETSI TeraFlowSDN - TFS OSG (https://tfs.etsi.org/) +* +* 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.etsi.tfs.ztp.exception; + +import io.grpc.Metadata; +import io.grpc.ServerCall; +import io.grpc.Status; +import io.grpc.StatusRuntimeException; +import io.quarkus.grpc.ExceptionHandlerProvider; +import jakarta.enterprise.context.ApplicationScoped; + +@ApplicationScoped +public class GeneralExceptionHandler implements ExceptionHandlerProvider { + @Override + public <ReqT, RespT> io.quarkus.grpc.ExceptionHandler<ReqT, RespT> createHandler( + ServerCall.Listener<ReqT> listener, ServerCall<ReqT, RespT> serverCall, Metadata metadata) { + return new HelloExceptionHandler<>(listener, serverCall, metadata); + } + + @Override + public Throwable transform(Throwable t) { + if (t instanceof ExternalServiceFailureException) { + return new StatusRuntimeException(Status.INTERNAL.withDescription(t.getMessage())); + } else { + return ExceptionHandlerProvider.toStatusException(t, true); + } + } + + private static class HelloExceptionHandler<A, B> extends io.quarkus.grpc.ExceptionHandler<A, B> { + public HelloExceptionHandler( + ServerCall.Listener<A> listener, ServerCall<A, B> call, Metadata metadata) { + super(listener, call, metadata); + } + + @Override + protected void handleException(Throwable t, ServerCall<A, B> call, Metadata metadata) { + StatusRuntimeException sre = + (StatusRuntimeException) ExceptionHandlerProvider.toStatusException(t, true); + Metadata trailers = sre.getTrailers() != null ? sre.getTrailers() : metadata; + call.close(sre.getStatus(), trailers); + } + } +} diff --git a/src/ztp/src/main/resources/application.yml b/src/ztp/src/main/resources/application.yml index c551759efb3645f9c307c20a8988fc8ee9a89e0a..91f40d0c281861ada31631099dad0d02f6e98a93 100644 --- a/src/ztp/src/main/resources/application.yml +++ b/src/ztp/src/main/resources/application.yml @@ -15,6 +15,11 @@ ztp: should-subscribe-to-context-component: true quarkus: + package: + type: mutable-jar + live-reload: + password: 1234 + url: http://0.0.0.0:8080 banner: path: teraflow-ztp-banner.txt grpc: