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

esa.mo.mal.impl.InteractionTimeout Maven / Gradle / Ivy

/* ----------------------------------------------------------------------------
 * Copyright (C) 2021      European Space Agency
 *                         European Space Operations Centre
 *                         Darmstadt
 *                         Germany
 * ----------------------------------------------------------------------------
 * System                : CCSDS MO MAL Java Implementation
 * ----------------------------------------------------------------------------
 * Licensed under the European Space Agency Public License, Version 2.0
 * You may not use this file except in compliance with the License.
 *
 * Except as expressly set forth in this License, the Software is provided to
 * You on an "as is" basis and without warranties of any kind, including without
 * limitation merchantability, fitness for a particular purpose, absence of
 * defects or errors, accuracy or non-infringement of intellectual property rights.
 * 
 * See the License for the specific language governing permissions and
 * limitations under the License. 
 * ----------------------------------------------------------------------------
 */
package esa.mo.mal.impl;

import esa.mo.mal.impl.state.BaseOperationHandler;
import java.util.AbstractMap.SimpleEntry;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.ccsds.moims.mo.mal.MALHelper;
import org.ccsds.moims.mo.mal.MALStandardError;

/**
 * The InteractionTimeout class is responsible for maintaining a queue of
 * transactions and checking if they have timed out.
 */
public class InteractionTimeout {

    // The property key to set the MAL Interaction Timeout
    private final static String PROP_INTERACTION_TIMEOUT
            = "org.ccsds.moims.mo.mal.interaction.timeout";

    /**
     * The queue that holds a set of entries with the time when interaction was
     * started and the respective operation handler.
     */
    private final LinkedBlockingQueue> queue
            = new LinkedBlockingQueue<>();

    // Defines if this object has been initialized
    private boolean initialized = false;

    // Defines if the MAL Interaction Timeout is enabled
    private boolean enabled = false;

    // The timeout in milliseconds
    private long timeout = 0;

    public InteractionTimeout() {
        // For testing purposes, one can use:
        // System.setProperty(PROP_INTERACTION_TIMEOUT, "1000"); // in ms
        Logger.getLogger(InteractionTimeout.class.getName()).log(
                Level.FINE, "New InteractionTimeout()");
    }

    private void initialize() {
        if (!initialized) {
            final String prop = System.getProperty(PROP_INTERACTION_TIMEOUT, null);

            if (prop != null) {
                try {
                    timeout = Long.valueOf(prop);
                    // 
                    if (timeout > 0) {
                        enabled = true;
                    }

                    if (enabled) {
                        Thread t1 = createTimeoutCheckingThread();
                        t1.setName("MAL_Interaction_Timeout_Thread");
                        t1.start();
                    }
                } catch (NumberFormatException ex) {
                    Logger.getLogger(InteractionTimeout.class.getName()).log(
                            Level.SEVERE,
                            "The MAL timeout property value must be a number. "
                            + "Please provide it with the key: "
                            + PROP_INTERACTION_TIMEOUT, ex);
                }
            }
        }

        initialized = true;
    }

    public synchronized void insertInQueue(BaseOperationHandler handler) {
        if (!initialized) {
            Logger.getLogger(InteractionTimeout.class.getName()).log(
                    Level.FINE, "Initializing Interaction Timeout Thread...");
            initialize();
        }

        if (enabled) {
            queue.add(new SimpleEntry(System.currentTimeMillis(), handler));
        }
    }

    private Thread createTimeoutCheckingThread() {
        return new Thread(() -> {
            while (true) {
                try {
                    SimpleEntry entry = queue.take();
                    long timeoutAt = entry.getKey() + timeout;
                    long sleepFor = timeoutAt - System.currentTimeMillis();
                    
                    // If the timeout was not reached yet
                    // then we sleep until we reach it
                    if (sleepFor > 0) {
                        try {
                            Thread.sleep(sleepFor);
                        } catch (InterruptedException ex) {
                            Logger.getLogger(InteractionTimeout.class.getName()).log(
                                    Level.SEVERE, "Something went wrong...", ex);
                        }
                    }
                    
                    BaseOperationHandler handler = entry.getValue();
                    
                    // Is the interaction still pending?
                    if (!handler.finished()) {
                        // Then we must trigger an Exception!
                        Logger.getLogger(InteractionTimeout.class.getName()).log(
                                Level.FINE, "Timeout triggered!");
                        
                        String msg = "The interaction timeout in the MAL "
                                + "was triggered! The timeout is currently "
                                + "set to: " + timeout + " ms";
                        
                            try {
                                handler.handleError(
                                        null,
                                        new MALStandardError(
                                                MALHelper.DELIVERY_TIMEDOUT_ERROR_NUMBER,
                                                msg),
                                        null);
                            } catch (Exception ex) {
                                // Do not allow to kill the thread
                                Logger.getLogger(InteractionTimeout.class.getName()).log(
                                    Level.SEVERE, "MAL error handler threw an exception!", ex);
                            }
                    }
                } catch (InterruptedException ex) {
                    Logger.getLogger(InteractionTimeout.class.getName()).log(
                            Level.SEVERE, "Something went wrong...", ex);
                }
            }
        });
    }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy