All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.bidib.wizard.server.controllers.firmware.FirmwareUpdateController Maven / Gradle / Ivy

There is a newer version: 2.0.29
Show newest version
package org.bidib.wizard.server.controllers.firmware;

import java.security.Principal;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;

import javax.annotation.PostConstruct;

import org.apache.commons.lang3.StringUtils;
import org.bidib.api.json.types.NodeAddress;
import org.bidib.api.json.types.NodeInfo;
import org.bidib.api.json.types.ProcessingStatusType;
import org.bidib.api.json.types.SystemError;
import org.bidib.api.json.types.firmware.DeviceNodeType;
import org.bidib.api.json.types.firmware.FirmwareNodeUpdate;
import org.bidib.api.json.types.firmware.FirmwareUpdateProgressInfo;
import org.bidib.api.json.types.firmware.FirmwareUpdateProgressInfo.SimpleFirmwareUpdateStatus;
import org.bidib.api.json.types.firmware.FirmwareVersionInfo;
import org.bidib.api.json.types.firmware.NodeFirmware;
import org.bidib.api.json.types.firmware.NodeFirmwareDetails;
import org.bidib.wizard.api.locale.Resources;
import org.bidib.wizard.api.model.NodeInterface;
import org.bidib.wizard.api.model.NodeProvider;
import org.bidib.wizard.api.model.connection.BidibConnection;
import org.bidib.wizard.api.notification.FirmwareUpdateStatus;
import org.bidib.wizard.api.notification.FirmwareUpdateStatus.FirmwareUpdateStatusAction;
import org.bidib.wizard.common.exception.ConnectionException;
import org.bidib.wizard.core.model.connection.ConnectionRegistry;
import org.bidib.wizard.core.service.FirmwareUpdateService;
import org.bidib.wizard.core.service.NodeFirmwareUpdateService;
import org.bidib.wizard.server.aspect.LogExecutionTime;
import org.bidib.wizard.server.config.StompDestinations;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.event.EventListener;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.messaging.handler.annotation.MessageExceptionHandler;
import org.springframework.messaging.handler.annotation.MessageMapping;
import org.springframework.messaging.simp.SimpMessagingTemplate;
import org.springframework.messaging.simp.annotation.SendToUser;
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import io.reactivex.rxjava3.subjects.SingleSubject;

@CrossOrigin(origins = "*")
@RestController
@RequestMapping("/api/firmware")
public class FirmwareUpdateController /* implements FirmwareUpdateStatusPublisher */ {
    private static final Logger LOGGER = LoggerFactory.getLogger(FirmwareUpdateController.class);

    @Autowired
    private FirmwareUpdateService firmwareUpdateService;

    @Autowired
    private ConnectionRegistry connectionRegistry;

    // The SimpMessagingTemplate is used to send Stomp over WebSocket messages.
    @Autowired
    private SimpMessagingTemplate messagingTemplate;

    public FirmwareUpdateController() {
    }

    private BidibConnection findConnection(final String connectionId) {

        BidibConnection connection = connectionRegistry.getConnection(connectionId);
        if (connection == null) {
            throw new ConnectionException("No connection available with id: " + connectionId);
        }
        LOGGER.debug("Found connection: {}", connection);
        return connection;
    }

    @PostConstruct
    public void initialize() {
        LOGGER.info("Initialize the FirmwareUpdateController.");
    }

    @GetMapping(path = "/availableFirmware")
    public ResponseEntity getAvailableFirmware() {

        LOGGER.debug("Get the available firmware.");

        List availableFirmware = firmwareUpdateService.queryAvailableFirmware();

        return new ResponseEntity<>(availableFirmware.toArray(new FirmwareVersionInfo[0]), HttpStatus.OK);
    }

    @MessageMapping("/firmware/nodes")
    @SendToUser(destinations = StompDestinations.FIRMWARE_NODES_DESTINATION, broadcast = false)
    @LogExecutionTime
    public FirmwareVersionInfo[] msgGetAvailableFirmware(String text) {

        LOGGER.info("Get the available firmware.");

        List availableFirmware = firmwareUpdateService.queryAvailableFirmware();
        return availableFirmware.toArray(new FirmwareVersionInfo[0]);
    }

    @MessageMapping("/firmware/details")
    @SendToUser(destinations = StompDestinations.FIRMWARE_DETAILS_DESTINATION, broadcast = false)
    @LogExecutionTime
    public NodeFirmware msgGetFirmwareDetails(NodeFirmwareDetails details) {
        int vendorId = details.getManufacturerId();
        int productId = details.getProductId();
        String version = details.getVersion();
        LOGGER
            .info("Get the firmware details, vendorId: {}, productId: {}, version: {}.", vendorId, productId, version);

        NodeFirmware nodeFirmware = firmwareUpdateService.getFirmwareDetails(vendorId, productId, version);
        return nodeFirmware;
    }

    @MessageMapping("/firmware/node/update")
    @SendToUser(destinations = StompDestinations.FIRMWARE_UPDATE_PROGRESS_DESTINATION, broadcast = false)
    @LogExecutionTime
    public FirmwareUpdateProgressInfo msgFirmwareNodeUpdate(Principal principal, FirmwareNodeUpdate nodeUpdate) {

        LOGGER.info("Update the node: {}, principal: {}", nodeUpdate, principal);

        String destinationQualifier = principal.getName();

        FirmwareVersionInfo version = nodeUpdate.getVersion();
        final NodeInfo ni = nodeUpdate.getNode();
        long uniqueId = Long.parseLong(ni.getUniqueId());

        String connectionId = nodeUpdate.getConnectionId();

        // find the matching node provider
        NodeProvider nodeProvider = findConnection(connectionId).getNodeProvider();

        FirmwareUpdateProgressInfo statusInfo = new FirmwareUpdateProgressInfo();
        statusInfo.setConnectionId(connectionId);
        statusInfo.setNode(ni);

        List nodesList = new ArrayList<>();
        NodeInterface node = nodeProvider.findNodeByUniqueId(uniqueId);
        if (node == null) {
            LOGGER.warn("The delivered node is not registered. Abort update.");
            statusInfo.setTotal(100);
            statusInfo.setProgress(0);
            statusInfo.setStatus(SimpleFirmwareUpdateStatus.FAILED);
            statusInfo
                .setMsgKey(Resources.prepareResourceKey(NodeFirmwareUpdateService.class, "status.node-not-found"));
            return statusInfo;
        }

        nodesList.add(node);

        // get the selected firmware information
        DeviceNodeType deviceNode = nodeUpdate.getDeviceNode();
        if (deviceNode == null) {
            LOGGER.warn("No device node delivered. Abort update.");
            statusInfo.setTotal(100);
            statusInfo.setProgress(0);
            statusInfo.setStatus(SimpleFirmwareUpdateStatus.FAILED);
            statusInfo
                .setMsgKey(Resources.prepareResourceKey(NodeFirmwareUpdateService.class, "status.device-node-missing"));
            return statusInfo;
        }

        final SingleSubject subjectFinished = SingleSubject.create();
        subjectFinished.subscribe(success -> {
            LOGGER.info("Firmware update finished, success: {}", success);
        }, ex -> {
            LOGGER.warn("Perform firmware update failed.", ex);
        });

        firmwareUpdateService
            .updateFirmware(ConnectionRegistry.CONNECTION_ID_MAIN, nodeUpdate.getFirmwarePath(), destinationQualifier,
                version, deviceNode, nodesList, subjectFinished);

        statusInfo.setNode(ni);

        statusInfo.setProgress(1);
        statusInfo.setTotal(100);
        statusInfo.setStatus(SimpleFirmwareUpdateStatus.RUNNING);

        return statusInfo;
    }

    @MessageExceptionHandler
    public String handleException(Throwable exception) {
        LOGGER.error("Error detected: ", exception);

        final SystemError se = new SystemError(exception.getMessage(), null, LocalDateTime.now(), null);
        messagingTemplate.convertAndSend(StompDestinations.SYSTEM_ERROR_DESTINATION, se);
        return exception.getMessage();
    }

    private void publishProgress(
        String connectionId, String destinationQualifier, String address, Long uniqueId, Integer progress,
        FirmwareUpdateStatusAction firmwareUpdateStatusAction, String msgKey) {

        LOGGER
            .info("Publish progress, destinationQualifier: {}, address: {}, uniqueId: {}, progress: {}, msgKey: {}",
                destinationQualifier, address, uniqueId, progress, msgKey);

        String destination = StompDestinations.FIRMWARE_UPDATE_PROGRESS_DESTINATION;

        FirmwareUpdateProgressInfo progressInfo = new FirmwareUpdateProgressInfo();
        progressInfo.setConnectionId(connectionId);

        if (uniqueId != null) {
            progressInfo.setNode(new NodeAddress().withUniqueId(uniqueId.toString()).withAddress(address));
        }
        if (progress != null) {
            progressInfo.setProgress(progress);
        }
        if (firmwareUpdateStatusAction != null) {
            progressInfo.setStatus(SimpleFirmwareUpdateStatus.valueOf(firmwareUpdateStatusAction.name()));
        }
        progressInfo.setMsgKey(msgKey);

        messagingTemplate.convertAndSendToUser(destinationQualifier, destination, progressInfo);
    }

    private void publishStatus(String destinationQualifier, Long uniqueId, ProcessingStatusType processingStatus) {

        LOGGER
            .info("Publish status, destinationQualifier: {}, uniqueId: {}, processingStatus: {}", destinationQualifier,
                uniqueId, processingStatus);

        String destination = StompDestinations.FIRMWARE_UPDATE_STATE_DESTINATION;

        messagingTemplate.convertAndSendToUser(destinationQualifier, destination, processingStatus);
    }

    private void publishProgress(String destinationQualifier, Long uniqueId, FirmwareUpdateProgressInfo progressInfo) {

        LOGGER
            .info("Publish progress, destinationQualifier: {}, uniqueId: {}, progressInfo: {}", destinationQualifier,
                uniqueId, progressInfo);

        String destination = StompDestinations.FIRMWARE_UPDATE_PROGRESS_DESTINATION;
        messagingTemplate.convertAndSendToUser(destinationQualifier, destination, progressInfo);
    }

    @EventListener
    public void eventHandler(final FirmwareUpdateStatus firmwareUpdateStatus) {
        LOGGER.info("Handle the firmwareUpdateStatus event: {}", firmwareUpdateStatus);

        if (StringUtils.isNotEmpty(firmwareUpdateStatus.getConnectionId())) {
            publishProgress(firmwareUpdateStatus.getConnectionId(), firmwareUpdateStatus.getDestinationQualifier(),
                firmwareUpdateStatus.getAddress(), firmwareUpdateStatus.getUniqueId(),
                firmwareUpdateStatus.getProgress(), firmwareUpdateStatus.getFirmwareUpdateStatusAction(),
                firmwareUpdateStatus.getMsgKey());
        }
        else if (firmwareUpdateStatus.getProcessingStatus() != null) {
            publishStatus(firmwareUpdateStatus.getDestinationQualifier(), firmwareUpdateStatus.getUniqueId(),
                firmwareUpdateStatus.getProcessingStatus());
        }
        else if (firmwareUpdateStatus.getProgressInfo() != null) {
            publishProgress(firmwareUpdateStatus.getDestinationQualifier(), firmwareUpdateStatus.getUniqueId(),
                firmwareUpdateStatus.getProgressInfo());
        }

    }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy