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

org.tango.server.events.ChangeEventTrigger Maven / Gradle / Ivy

The newest version!
/**
 * Copyright (C) :     2012
 *
 * 	Synchrotron Soleil
 * 	L'Orme des merisiers
 * 	Saint Aubin
 * 	BP48
 * 	91192 GIF-SUR-YVETTE CEDEX
 *
 * This file is part of Tango.
 *
 * Tango is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * Tango is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with Tango.  If not, see .
 */
package org.tango.server.events;

import java.lang.reflect.Array;
import java.util.Arrays;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.slf4j.ext.XLogger;
import org.slf4j.ext.XLoggerFactory;
import org.tango.server.Constants;
import org.tango.server.ExceptionMessages;
import org.tango.server.attribute.AttributeImpl;
import org.tango.server.attribute.AttributeValue;
import org.tango.utils.ArrayUtils;
import org.tango.utils.DevFailedUtils;

import fr.esrf.Tango.DevEncoded;
import fr.esrf.Tango.DevFailed;
import fr.esrf.Tango.DevState;
import fr.esrf.Tango.EventProperties;

/**
 * manage trigger for {@link EventType#CHANGE_EVENT}
 *
 * @author ABEILLE
 *
 */
public class ChangeEventTrigger implements IEventTrigger {

    private final Logger logger = LoggerFactory.getLogger(ChangeEventTrigger.class);
    private final XLogger xlogger = XLoggerFactory.getXLogger(ChangeEventTrigger.class);
    private final AttributeImpl attribute;
    private AttributeValue previousValue;
    private AttributeValue value;
    private double absolute;
    private boolean checkAbsolute;
    private double relative;
    private boolean checkRelative;
    private DevFailed error;
    private DevFailed previousError;
    private boolean previousInitialized = false;
    private final QualityEventTrigger qualityTrigger;

    /**
     * Ctr
     *
     * @param attribute The attribute that send event
     * @param absolute The absolute change delta
     * @param relative The relative change delta
     */
    public ChangeEventTrigger(final AttributeImpl attribute, final String absolute, final String relative) {
        this.attribute = attribute;
        value = attribute.getReadValue();
        qualityTrigger = new QualityEventTrigger(attribute);
        setCriteria(absolute, relative);
    }

    public void setCriteria(final String absolute, final String relative) {
        try {
            this.absolute = Double.parseDouble(absolute);
            checkAbsolute = true;
        } catch (final NumberFormatException e) {
            checkAbsolute = false;
        }
        try {
            this.relative = Double.parseDouble(relative);
            checkRelative = true;
        } catch (final NumberFormatException e) {
            checkRelative = false;
        }
    }

    @Override
    public boolean isSendEvent() throws DevFailed {
        xlogger.entry();
        boolean hasChanged = qualityTrigger.isSendEvent();
        if (!hasChanged) {
            value = attribute.getReadValue();
            // Check if first call
            if (!previousInitialized) {
                previousError = error;
                previousValue = value;
                previousInitialized = true;
                hasChanged = true;
            } else {
                if (previousError != null && error == null) {
                    // there was an error before
                    hasChanged = true;
                } else if (previousError == null && error != null) {
                    // an error has just occured
                    hasChanged = true;
                } else if (previousError != null && error != null) {
                    if (!DevFailedUtils.toString(previousError).equals(DevFailedUtils.toString(error))) {
                        // the error msg has changed
                        hasChanged = true;
                    }
                } else if (value.getValue() == null && previousValue.getValue() == null) {
                    hasChanged = false;
                } else if (value.getValue() == null && previousValue.getValue() != null) {
                    hasChanged = true;
                } else if (value.getValue() != null && previousValue.getValue() == null) {
                    hasChanged = true;
                } else if (attribute.isScalar()) {
                    if (attribute.isNumber()) {
                        hasChanged = hasScalarNumberChanged();
                    } else if (attribute.isState()) {
                        hasChanged = hasStateChanged();
                    } else if (attribute.isDevEncoded()) {
                        hasChanged = hasDevEncodedChanged();
                    } else {
                        // string or boolean
                        hasChanged = hasScalarStringChanged();
                    }
                } else {
                    if (attribute.isNumber()) {
                        hasChanged = hasArrayNumberChanged();
                    } else if (attribute.isState()) {
                        hasChanged = hasStateArrayChanged();
                    } else {
                        // string or boolean
                        hasChanged = hasArrayStringChanged();
                    }
                }
                if (hasChanged) {
                    previousValue = value;
                }
            }
        }
        logger.debug("CHANGE event for {} must send: {}", attribute.getName(), hasChanged);
        xlogger.exit();
        return hasChanged;
    }

    @Override
    public void setError(final DevFailed error) {
        previousError = this.error;
        this.error = error;
    }

    private boolean hasScalarNumberChanged() {
        boolean hasChanged = false;
        final double val = Double.parseDouble(value.getValue().toString());
        final double previousVal = Double.parseDouble(previousValue.getValue().toString());
        // absolute change
        if (checkAbsolute) {
            final double delta = val - previousVal;
            hasChanged = Math.abs(delta) >= absolute;
        }
        // relative change
        if (!hasChanged && checkRelative) {
            final double delta;
            if (previousVal == 0) {
                if (val == 0) {
                    delta = 0;
                } else {
                    delta = 100;
                }
            } else {
                delta = (val - previousVal) / previousVal * 100.0;
            }
            hasChanged = Math.abs(delta) >= relative;
        }
        return hasChanged;
    }

    private boolean hasDevEncodedChanged() {
        final DevEncoded val = (DevEncoded) value.getValue();
        final DevEncoded previousVal = (DevEncoded) previousValue.getValue();
        return !Arrays.equals(val.encoded_data, previousVal.encoded_data);
    }

    private boolean hasScalarStringChanged() {
        final String val = value.getValue().toString();
        final String previousVal = previousValue.getValue().toString();
        return !val.equals(previousVal);
    }

    private boolean hasArrayNumberChanged() {
        boolean hasChanged = false;
        if (Array.getLength(value.getValue()) != Array.getLength(previousValue.getValue())) {
            hasChanged = true;
        } else {
            final String[] val = ArrayUtils.toStringArray(value.getValue());
            final String[] previousVal = ArrayUtils.toStringArray(previousValue.getValue());
            for (int i = 0; i < previousVal.length; i++) {
                final double valD = Double.parseDouble(val[i]);
                final double previousValD = Double.parseDouble(previousVal[i]);
                // absolute change
                if (checkAbsolute) {
                    final double delta = valD - previousValD;
                    hasChanged = Math.abs(delta) >= absolute;
                }
                // relative change
                if (!hasChanged && checkRelative) {
                    final double delta;
                    if (previousValD == 0) {
                        if (valD == 0) {
                            delta = 0;
                        } else {
                            delta = 100;
                        }
                    } else {
                        delta = valD - previousValD * 100.0 / previousValD;
                    }
                    hasChanged = Math.abs(delta) >= relative;
                }
                if (hasChanged) {
                    break;
                }
            }
        }
        return hasChanged;
    }

    private boolean hasArrayStringChanged() {
        boolean hasChanged = false;

        if (Array.getLength(value.getValue()) != Array.getLength(previousValue.getValue())) {
            hasChanged = true;
        } else {
            final String[] val;
            final String[] previousVal;
            if (value.getValue() instanceof String[]) {
                val = (String[]) value.getValue();
                previousVal = (String[]) previousValue.getValue();
            } else {
                val = ArrayUtils.toStringArray(value.getValue());
                previousVal = ArrayUtils.toStringArray(previousValue.getValue());
            }
            if (!Arrays.equals(val, previousVal)) {
                hasChanged = true;
            }
        }
        return hasChanged;
    }

    private boolean hasStateChanged() {
        final DevState state = (DevState) value.getValue();
        final DevState previousState = (DevState) previousValue.getValue();
        return state != previousState;
    }

    private boolean hasStateArrayChanged() {
        boolean hasChanged = false;
        final DevState[] state = (DevState[]) value.getValue();
        final DevState[] previousState = (DevState[]) previousValue.getValue();
        if (state.length != previousState.length) {
            hasChanged = true;
        } else {
            for (int i = 0; i < previousState.length; i++) {
                if (!state[i].equals(previousState[i])) {
                    hasChanged = true;
                    break;
                }
            }
        }
        return hasChanged;
    }

    /**
     * Check if event criteria are set for specified events
     *
     * @param attribute the specified attribute
     * @throws DevFailed if no event criteria is set for specified attribute.
     */
    static void checkEventCriteria(final AttributeImpl attribute) throws DevFailed {
        // Check if value is not numerical (always true for State and String)
        if (attribute.isState() || attribute.isString() || attribute.isBoolean()) {
            return;
        }
        // Else check criteria
        final EventProperties props = attribute.getProperties().getEventProp();
        if (props.ch_event.abs_change.equals(Constants.NOT_SPECIFIED)
                && props.ch_event.rel_change.equals(Constants.NOT_SPECIFIED)) {
            DevFailedUtils
                    .throwDevFailed(ExceptionMessages.EVENT_CRITERIA_NOT_SET,
                            "Event properties (abs_change or rel_change) for attribute " + attribute.getName()
                                    + " are not set");
        }
    }

    @Override
    public void updateProperties() throws DevFailed {
        final EventProperties props = attribute.getProperties().getEventProp();
        setCriteria(props.ch_event.abs_change, props.ch_event.rel_change);
    }

    @Override
    public boolean doCheck() {
        return attribute.isPushChangeEvent() ? attribute.isCheckChangeEvent() : true;
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy