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

net.sf.jrtps.QualityOfService Maven / Gradle / Ivy

package net.sf.jrtps;

import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.concurrent.CopyOnWriteArrayList;

import net.sf.jrtps.message.parameter.Changeable;
import net.sf.jrtps.message.parameter.DataReaderPolicy;
import net.sf.jrtps.message.parameter.DataWriterPolicy;
import net.sf.jrtps.message.parameter.InlineQoS;
import net.sf.jrtps.message.parameter.Parameter;
import net.sf.jrtps.message.parameter.QosDataRepresentation;
import net.sf.jrtps.message.parameter.QosDeadline;
import net.sf.jrtps.message.parameter.QosDestinationOrder;
import net.sf.jrtps.message.parameter.QosDurability;
import net.sf.jrtps.message.parameter.QosDurabilityService;
import net.sf.jrtps.message.parameter.QosGroupData;
import net.sf.jrtps.message.parameter.QosHistory;
import net.sf.jrtps.message.parameter.QosLatencyBudget;
import net.sf.jrtps.message.parameter.QosLifespan;
import net.sf.jrtps.message.parameter.QosLiveliness;
import net.sf.jrtps.message.parameter.QosOwnership;
import net.sf.jrtps.message.parameter.QosOwnershipStrength;
import net.sf.jrtps.message.parameter.QosPartition;
import net.sf.jrtps.message.parameter.QosPolicy;
import net.sf.jrtps.message.parameter.QosPresentation;
import net.sf.jrtps.message.parameter.QosReliability;
import net.sf.jrtps.message.parameter.QosResourceLimits;
import net.sf.jrtps.message.parameter.QosTimeBasedFilter;
import net.sf.jrtps.message.parameter.QosTopicData;
import net.sf.jrtps.message.parameter.QosTransportPriority;
import net.sf.jrtps.message.parameter.QosTypeConsistencyEnforcement;
import net.sf.jrtps.message.parameter.QosUserData;
import net.sf.jrtps.message.parameter.TopicPolicy;
import net.sf.jrtps.types.Duration;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * QualityOfService holds a collection QosPolicies.
 * 
 * @author mcr70
 * 
 */
@SuppressWarnings("rawtypes")
public class QualityOfService {
	private static final Logger logger = LoggerFactory.getLogger(QualityOfService.class);

    private static final QualityOfService sedpQos = createSEDPQualityOfService();
    private static final QualityOfService spdpQos = createSPDPQualityOfService();
    
    private final List policyListeners = new CopyOnWriteArrayList(); 
    private final HashMap, QosPolicy> policies = new HashMap<>();

    /**
     * Constructor with default QosPolicies.
     */
    public QualityOfService() {
    }

    /**
     * Sets a given QosPolicy. Old value will be overridden.
     * 
     * @param policy QosPolicy to set.
     * @throws InconsistentPolicy is thrown if there is some inconsistent value with the policy
     */
    public void setPolicy(QosPolicy policy) throws InconsistentPolicy {
    	if (!(policy instanceof Changeable)) {
    		synchronized (policies) {
    			if (policies.containsKey(policy.getClass())) {
    				logger.debug("{} was already within this QualityOfService: {}", policy.getClass(),
    						policies.keySet());
    				throw new IllegalArgumentException(policy.getClass().getSimpleName() + 
    						" is not Changeable; cannot set twice");
    			}
    		}
		}
    	
    	checkForInconsistencies(policy);

        policies.put(policy.getClass(), policy);
        notifyPolicyChanged(policy);
    }

    private void notifyPolicyChanged(QosPolicy policy) {
    	for (PolicyListener listener : policyListeners) {
    		listener.policyChanged(policy);
    	}
    }

	private void checkForInconsistencies(QosPolicy policy) throws InconsistentPolicy {
        if (policy instanceof QosDeadline) { // ---  DEADLINE  ---
            QosTimeBasedFilter tbf = (QosTimeBasedFilter) policies.get(QosTimeBasedFilter.class);
            if (tbf == null) {
                tbf = QosTimeBasedFilter.defaultTimeBasedFilter();
            }

            QosDeadline dl = (QosDeadline) policy;
            if (dl.getPeriod().asMillis() < tbf.getMinimumSeparation().asMillis()) {
                throw new InconsistentPolicy("DEADLINE.period(" + dl.getPeriod()
                        + ") must be >= TIME_BASED_FILTER.minimum_separation(" + tbf.getMinimumSeparation() + ")");
            }
        } 
        else if (policy instanceof QosTimeBasedFilter) { // ---  TIME_BASED_FILTER  ---
            QosDeadline dl = (QosDeadline) policies.get(QosDeadline.class);
            if (dl == null) {
                dl = QosDeadline.defaultDeadline();
            }

            QosTimeBasedFilter tbf = (QosTimeBasedFilter) policy;
            if (dl.getPeriod().asMillis() < tbf.getMinimumSeparation().asMillis()) {
                throw new InconsistentPolicy("DEADLINE.period(" + dl.getPeriod()
                        + ") must be >= TIME_BASED_FILTER.minimum_separation(" + tbf.getMinimumSeparation() + ")");
            }
        } 
        else if (policy instanceof QosHistory) { // ---  HISTORY  ---
            QosResourceLimits rl = (QosResourceLimits) policies.get(QosResourceLimits.class);
            if (rl == null) {
                rl = QosResourceLimits.defaultResourceLimits();
            }

            QosHistory h = (QosHistory) policy;

            if (rl.getMaxSamplesPerInstance() != -1 && 
                    QosHistory.Kind.KEEP_LAST == h.getKind() &&
                    rl.getMaxSamplesPerInstance() < h.getDepth()) {
                throw new InconsistentPolicy("HISTORY.depth must be <= RESOURCE_LIMITS.max_samples_per_instance");
            }
        } 
        else if (policy instanceof QosResourceLimits) { // ---  RESOURCE_LIMITS  ---
            QosResourceLimits rl = (QosResourceLimits) policy;
            if (rl.getMaxSamples() < rl.getMaxSamplesPerInstance()) {
                throw new InconsistentPolicy(
                        "RESOURCE_LIMITS.max_samples must be >= RESOURCE_LIMITS.max_samples_per_instance");
            }

            QosHistory h = (QosHistory) policies.get(QosHistory.class);
            if (h == null) {
                h = QosHistory.defaultHistory();
            }

            if (rl.getMaxSamplesPerInstance() != -1 && rl.getMaxSamplesPerInstance() < h.getDepth()) {
                throw new InconsistentPolicy("HISTORY.depth must be <= RESOURCE_LIMITS.max_samples_per_instance");
            }
        }
    }

    /**
     * Gets all the DataReaderPolicies from this QualityOfService. A new Set is
     * always created when calling this method. Changes to returned Set is not
     * reflected back to this QualityOfService.
     * 
     * @return Data reader policies
     */
    public Set getReaderPolicies() {
        Set readerPolicies = new HashSet<>();

        for (QosPolicy qp : policies.values()) {
            if (qp instanceof DataReaderPolicy) {
                readerPolicies.add((DataReaderPolicy) qp);
            }
        }

        return readerPolicies;
    }

    /**
     * Gets all the DataWriterPolicies from this QualityOfService. A new Set is
     * always created when calling this method. Changes to returned Set is not
     * reflected back to this QualityOfService.
     * 
     * @return Data writer policies
     */
    public Set getWriterPolicies() {
        Set writerPolicies = new HashSet<>();

        for (QosPolicy qp : policies.values()) {
            if (qp instanceof DataWriterPolicy) {
                writerPolicies.add((DataWriterPolicy) qp);
            }
        }

        return writerPolicies;
    }

    /**
     * Gets all the TopicPolicies from this QualityOfService. A new Set is
     * always created when calling this method. Changes to returned Set is not
     * reflected back to this QualityOfService.
     * 
     * @return Topic policies
     */
    public Set getTopicPolicies() {
        Set topicPolicies = new HashSet<>();

        for (QosPolicy qp : policies.values()) {
            if (qp instanceof TopicPolicy) {
                topicPolicies.add((TopicPolicy) qp);
            }
        }

        return topicPolicies;
    }

    /**
     * Gets all the inlineable QosPolicies from this QualityOfService. A new Set
     * is always created when calling this method. Changes to returned Set is
     * not reflected back to this QualityOfService.
     * 
     * @return Inlineable QosPolicies
     */
    public Set> getInlinePolicies() {
        Set> inlinePolicies = new HashSet<>();

        for (QosPolicy qp : policies.values()) {
            if (qp instanceof InlineQoS) {
                inlinePolicies.add(qp);
            }
        }

        return inlinePolicies;
    }

    /**
     * Gets all the incompatible policies that are found from either QualityOfService.
     * I.e. check only policies that are explicitly set on either QualityOfService. 

     * @param other Other QoS 
     * @return a Set of QosPolicies. If all the policies are compatible, return an empty Set.
     */
    @SuppressWarnings("unchecked")
    public Set> getIncompatibleQos(QualityOfService other) {
        // Join qos policies defined in both QoS
        Set> commonSet = new HashSet<>();
        commonSet.addAll(policies.keySet());
        commonSet.addAll(other.policies.keySet());
        
        Set> set = new HashSet<>();

        // Loop through each qos policy defined in either of the QoS
        for (Class clazz : commonSet) {
            if (!Parameter.class.isAssignableFrom(clazz)) {
                continue;
            }
            
            QosPolicy qp = policies.get(clazz);
            if (qp == null) {
                qp = getDefaultFor(clazz); // get default for 'this'
            }
            
            QosPolicy qpOther = other.policies.get(clazz);
            if (qpOther == null) {
                qpOther = other.getDefaultFor(clazz); // get default for 'other'
            }
            
            if (!qp.isCompatible(qpOther)) {
                set.add(qpOther);
                logger.warn("Offered QosPolicy {} is not compatible with requested {}", qp, qpOther);
            }
        }

        return set;        
    }
    
    private QosPolicy getDefaultFor(Class clazz) {
        if (QosDeadline.class.equals(clazz)) {
            return QosDeadline.defaultDeadline();
        }
        else if (QosDestinationOrder.class.equals(clazz)) {
            return QosDestinationOrder.defaultDestinationOrder();
        }
        else if (QosDurability.class.equals(clazz)) {
            return QosDurability.defaultDurability();
        }
        else if (QosDurabilityService.class.equals(clazz)) {
            return QosDurabilityService.defaultDurabilityService();
        }
        else if (QosGroupData.class.equals(clazz)) {
            return QosGroupData.defaultGroupData();
        }
        else if (QosHistory.class.equals(clazz)) {
            return QosHistory.defaultHistory();
        }
        else if (QosLatencyBudget.class.equals(clazz)) {
            return QosLatencyBudget.defaultLatencyBudget();
        }
        else if (QosLifespan.class.equals(clazz)) {
            return QosLifespan.defaultLifespan();
        }
        else if (QosLiveliness.class.equals(clazz)) {
            return QosLiveliness.defaultLiveliness();
        }
        else if (QosOwnership.class.equals(clazz)) {
            return QosOwnership.defaultOwnership();
        }
        else if (QosOwnershipStrength.class.equals(clazz)) {
            return QosOwnershipStrength.defaultOwnershipStrength();
        }
        else if (QosPartition.class.equals(clazz)) {
            return QosPartition.defaultPartition();
        }
        else if (QosPresentation.class.equals(clazz)) {
            return QosPresentation.defaultPresentation();
        }
        else if (QosOwnershipStrength.class.equals(clazz)) {
            return QosOwnershipStrength.defaultOwnershipStrength();
        }
        else if (QosReliability.class.equals(clazz)) {
            return QosReliability.defaultReliability();
        }
        else if (QosResourceLimits.class.equals(clazz)) {
            return QosResourceLimits.defaultResourceLimits();
        }
        else if (QosTopicData.class.equals(clazz)) {
            return QosTopicData.defaultTopicData();
        }
        else if (QosTransportPriority.class.equals(clazz)) {
            return QosTransportPriority.defaultTransportPriority();
        }
        else if (QosTimeBasedFilter.class.equals(clazz)) {
            return QosTimeBasedFilter.defaultTimeBasedFilter();
        }
        else if (QosUserData.class.equals(clazz)) {
            return QosUserData.defaultUserData();
        }
        else if (QosTypeConsistencyEnforcement.class.equals(clazz)) {
            return QosTypeConsistencyEnforcement.defaultTypeConsistencyEnforcement();
        }

        logger.warn("Don't know how to get default for {}", clazz);

        return null;
    }

    /**
     * Checks wheter or not this QualityOfService is compatible with the other.
     * @param other Other QualityOfService
     * @return true, if compatible
     */
    public boolean isCompatibleWith(QualityOfService other) {
        return getIncompatibleQos(other).size() == 0;
    }

    /**
     * Gets the QualityOfService used in Simple Endpoint Discovery
     * Protocol(SEDP)
     * 
     * @return QualityOfService for SEDP
     */
    public static QualityOfService getSEDPQualityOfService() {
        return sedpQos;
    }

    /**
     * Gets the QualityOfService used in Simple Participant Discovery
     * Protocol(SPDP)
     * 
     * @return QualityOfService for SPDP
     */
    public static QualityOfService getSPDPQualityOfService() {
        return spdpQos;
    }


    /**
     * Gets the DataRepresentation QosPolicy
     * @return QosDataRepresentation
     */
    public QosDataRepresentation getDataRepresentation() {
        QosPolicy policy = policies.get(QosDataRepresentation.class);
        if (policy != null) {
            return (QosDataRepresentation) policy;
        }
        
        return QosDataRepresentation.defaultDataRepresentation();
    }
    
    /**
     * Gets the Deadline QosPolicy
     * @return QosDeadline
     */
    public QosDeadline getDeadline() {
        QosPolicy policy = policies.get(QosDeadline.class);
        if (policy != null) {
            return (QosDeadline) policy;
        }
        
        return QosDeadline.defaultDeadline();
    }

    /**
     * Gets the Deadline QosPolicy
     * @return QosDeadline
     */
    public QosDestinationOrder getDestinationOrder() {
        QosPolicy policy = policies.get(QosDestinationOrder.class);
        if (policy != null) {
            return (QosDestinationOrder) policy;
        }
        
        return QosDestinationOrder.defaultDestinationOrder();
    }

    /**
     * Gets the Durability QosPolicy
     * @return QosDurability
     */
    public QosDurability getDurability() {
        QosPolicy policy = policies.get(QosDurability.class);
        if (policy != null) {
            return (QosDurability) policy;
        }
        
        return QosDurability.defaultDurability(); 
    }

    /**
     * Gets the DurabilityService QosPolicy
     * @return QosDurability
     */
    public QosDurabilityService getDurabilityService() {
        QosPolicy policy = policies.get(QosDurabilityService.class);
        if (policy != null) {
            return (QosDurabilityService) policy;
        }
        
        return QosDurabilityService.defaultDurabilityService(); 
    }

    /**
     * Gets the GroupData QosPolicy
     * @return QosGroupData
     */
    public QosGroupData getGroupData() { 
        QosPolicy policy = policies.get(QosGroupData.class);
        if (policy != null) {
            return (QosGroupData) policy;
        }
        
        return QosGroupData.defaultGroupData(); 
    }

    /**
     * Gets the History QosPolicy
     * @return QosHistory
     */
    public QosHistory getHistory() { 
        QosPolicy policy = policies.get(QosHistory.class);
        if (policy != null) {
            return (QosHistory) policy;
        }
        
        return QosHistory.defaultHistory(); 
    }

    /**
     * Gets the LatencyBudget QosPolicy
     * @return QosLatencyBudget
     */
    public QosLatencyBudget getLatencyBudget() { 
        QosPolicy policy = policies.get(QosLatencyBudget.class);
        if (policy != null) {
            return (QosLatencyBudget) policy;
        }
        
        return QosLatencyBudget.defaultLatencyBudget();
    }

    /**
     * Gets the Lifespan QosPolicy
     * @return QosLifespan
     */
    public QosLifespan getLifespan() {
        QosPolicy policy = policies.get(QosLifespan.class);
        if (policy != null) {
            return (QosLifespan) policy;
        }
        
        return QosLifespan.defaultLifespan();
    }

    /**
     * Gets the Liveliness QosPolicy
     * @return QosLiveliness
     */
    public QosLiveliness getLiveliness() {
        QosPolicy policy = policies.get(QosLiveliness.class);
        if (policy != null) {
            return (QosLiveliness) policy;
        }
        
        return QosLiveliness.defaultLiveliness();
    }

    /**
     * Gets the Ownership QosPolicy
     * @return QosOwnership
     */
    public QosOwnership getOwnership() { 
        QosPolicy policy = policies.get(QosOwnership.class);
        if (policy != null) {
            return (QosOwnership) policy;
        }
        
        return QosOwnership.defaultOwnership();  
    }
    
    /**
     * Gets the OwnershipStrength QosPolicy
     * @return QosOwnershipStrength
     */
    public QosOwnershipStrength getOwnershipStrength() { 
        QosPolicy policy = policies.get(QosOwnershipStrength.class);
        if (policy != null) {
            return (QosOwnershipStrength) policy;
        }
        
        return QosOwnershipStrength.defaultOwnershipStrength();  
    }
    
    /**
     * Gets the Partition QosPolicy
     * @return QosPartition
     */
    public QosPartition getPartition() { 
        QosPolicy policy = policies.get(QosPartition.class);
        if (policy != null) {
            return (QosPartition) policy;
        }
        
        return QosPartition.defaultPartition();  
    }

    /**
     * Gets the Presentation QosPolicy
     * @return QosPresentation
     */
    public QosPresentation getPresentation() { 
        QosPolicy policy = policies.get(QosPresentation.class);
        if (policy != null) {
            return (QosPresentation) policy;
        }
        
        return QosPresentation.defaultPresentation();  
    }

    /**
     * Gets the Reliability QosPolicy
     * @return QosReliability
     */
    public QosReliability getReliability() { 
        QosPolicy policy = policies.get(QosReliability.class);
        if (policy != null) {
            return (QosReliability) policy;
        }
        
        return QosReliability.defaultReliability(); 
    }

    /**
     * Gets the ResourceLimits QosPolicy
     * @return QosResourceLimits
     */
    public QosResourceLimits getResourceLimits() { 
        QosPolicy policy = policies.get(QosResourceLimits.class);
        if (policy != null) {
            return (QosResourceLimits) policy;
        }
        
        return QosResourceLimits.defaultResourceLimits(); 
    }

    /**
     * Gets the TopicData QosPolicy
     * @return QosTopicData
     */
    public QosTopicData getTopicData() { 
        QosPolicy policy = policies.get(QosTopicData.class);
        if (policy != null) {
            return (QosTopicData) policy;
        }
        
        return QosTopicData.defaultTopicData(); 
    }

    /**
     * Gets the TransportPriority QosPolicy
     * @return QosTransportPriority
     */
    public QosTransportPriority getTransportPriority() { 
        QosPolicy policy = policies.get(QosTransportPriority.class);
        if (policy != null) {
            return (QosTransportPriority) policy;
        }
        
        return QosTransportPriority.defaultTransportPriority();
    }

    /**
     * Gets the TimeBasedFilter QosPolicy
     * @return QosTimeBasedFilter
     */
    public QosTimeBasedFilter getTimeBasedFilter() { 
        QosPolicy policy = policies.get(QosTimeBasedFilter.class);
        if (policy != null) {
            return (QosTimeBasedFilter) policy;
        }
        
        return QosTimeBasedFilter.defaultTimeBasedFilter(); 
    }

    /**
     * Gets the TransportPriority QosPolicy
     * @return QosTransportPriority
     */
    public QosUserData getUserData() { 
        QosPolicy policy = policies.get(QosUserData.class);
        if (policy != null) {
            return (QosUserData) policy;
        }
        
        return QosUserData.defaultUserData();
    }

    
    public QosTypeConsistencyEnforcement getTypeConsistencyEnforcement() {
        QosPolicy policy = policies.get(QosTypeConsistencyEnforcement.class);
        if (policy != null) {
            return (QosTypeConsistencyEnforcement) policy;
        }
        
        return QosTypeConsistencyEnforcement.defaultTypeConsistencyEnforcement();
    }

    
    private static QualityOfService createSEDPQualityOfService() {
        QualityOfService qos = new QualityOfService();
        try {
            qos.setPolicy(new QosDurability(QosDurability.Kind.TRANSIENT)); 
            // TODO: OSPL uses TRANSIENT, while TRANSIENT_LOCAL would be correct
            
            //qos.setPolicy(new QosPartition(new String[]{".*"})); // TODO: OSPL has "__BUILT-IN PARTITION__"
            
            qos.setPolicy(new QosPresentation(QosPresentation.Kind.TOPIC, false, false));
            qos.setPolicy(new QosDeadline(Duration.INFINITE));
            qos.setPolicy(new QosOwnership(QosOwnership.Kind.SHARED));
            qos.setPolicy(new QosLiveliness(QosLiveliness.Kind.AUTOMATIC, new Duration(0, 0)));
            qos.setPolicy(new QosTimeBasedFilter(new Duration(0)));
            qos.setPolicy(new QosReliability(QosReliability.Kind.RELIABLE, new Duration(100)));
            qos.setPolicy(new QosDestinationOrder(QosDestinationOrder.Kind.BY_RECEPTION_TIMESTAMP));
            qos.setPolicy(new QosHistory(QosHistory.Kind.KEEP_LAST, 1));
            qos.setPolicy(new QosResourceLimits(Integer.MAX_VALUE, Integer.MAX_VALUE, Integer.MAX_VALUE));
        } catch (InconsistentPolicy e) {
            throw new RuntimeException("Internal error", e);
        }

        return qos;
    }

    private static QualityOfService createSPDPQualityOfService() {
        QualityOfService qos = new QualityOfService();
        try {
            qos.setPolicy(new QosDurability(QosDurability.Kind.TRANSIENT_LOCAL));
            qos.setPolicy(new QosReliability(QosReliability.Kind.BEST_EFFORT, new Duration(0)));
        } catch (InconsistentPolicy e) {
            throw new RuntimeException("Internal error", e);
        }

        return qos;
    }

    public String toString() {
        return policies.values().toString();
    }

    
    public void addPolicyListener(PolicyListener listener) {
    	policyListeners.add(listener);
    }
    
    /**
     * PolicyChangedListener can be used to track changes to QualityOfService.
     * 
     * @author mcr70
     */
    public interface PolicyListener {
    	void policyChanged(QosPolicy policy);
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy