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

org.opentcs.data.TCSObject Maven / Gradle / Ivy

There is a newer version: 6.2.0
Show newest version
/**
 * Copyright (c) The openTCS Authors.
 *
 * This program is free software and subject to the MIT license. (For details,
 * see the licensing information (LICENSE.txt) you should have received with
 * this copy of the software.)
 */
package org.opentcs.data;

import java.io.Serializable;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import static java.util.Objects.requireNonNull;
import java.util.Set;
import java.util.stream.Collectors;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;

/**
 * Describes the base behaviour of TCS data objects.
 *
 * @author Stefan Walter (Fraunhofer IML)
 * @param  The actual object class.
 */
public abstract class TCSObject>
    implements Serializable {

  /**
   * A transient reference to this business object.
   */
  protected TCSObjectReference reference;
  /**
   * A set of properties (key-value pairs) associated with this object.
   */
  private final Map properties;
  /**
   * An unmodifiable view on this object's properties.
   * This mainly exists for {@link #getProperties()}, as the alternative of
   * creating ad-hoc copies or unmodifiable views can lead to performance issues
   * related to garbage collection in situations where {@link #getProperties()}
   * is called often.
   */
  private final Map propertiesReadOnly;
  /**
   * The name of the business object.
   */
  private final String name;
  /**
   * A history of events related to this object.
   */
  private final ObjectHistory history;

  /**
   * Creates a new TCSObject.
   *
   * @param objectName The new object's name.
   */
  protected TCSObject(@Nonnull String objectName) {
    this(objectName, new HashMap<>(), new ObjectHistory());
  }

  /**
   * Creates a new TCSObject.
   *
   * @param objectName The new object's name.
   * @param properties A set of properties (key-value pairs) associated with this object.
   * @param history A history of events related to this object.
   */
  protected TCSObject(@Nonnull String objectName,
                      @Nonnull Map properties,
                      @Nonnull ObjectHistory history) {
    this.name = requireNonNull(objectName, "objectName");
    this.properties = mapWithoutNullValues(properties);
    this.propertiesReadOnly = Collections.unmodifiableMap(this.properties);
    this.reference = new TCSObjectReference<>(this);
    this.history = requireNonNull(history, "history");
  }

  /**
   * Returns this object's name.
   *
   * @return This object's name.
   */
  @Nonnull
  public String getName() {
    return name;
  }

  /**
   * Returns a transient/soft reference to this object.
   *
   * @return A transient/soft reference to this object.
   */
  public TCSObjectReference getReference() {
    return reference;
  }

  /**
   * Returns an unmodifiable view on this object's properties.
   *
   * @return This object's properties.
   */
  @Nonnull
  public Map getProperties() {
    return propertiesReadOnly;
  }

  /**
   * Returns the property value for the given key.
   * This is basically a shortcut for getProperties().get(key).
   *
   * @param key The property's key.
   * @return The property value for the given key, or null, if there is none.
   */
  @Nullable
  public String getProperty(String key) {
    return properties.get(key);
  }

  /**
   * Creates a copy of this object, with the given property integrated.
   *
   * @param key The key of the property to be changed.
   * @param value The new value of the property, or null, if the property is to be
   * removed.
   * @return A copy of this object, with the given property integrated.
   */
  public abstract TCSObject withProperty(String key, String value);

  /**
   * Creates a copy of this object, with the given properties.
   *
   * @param properties The properties.
   * @return A copy of this object, with the given properties.
   */
  public abstract TCSObject withProperties(Map properties);

  public ObjectHistory getHistory() {
    return history;
  }

  /**
   * Creates a copy of this object, with the given history entry integrated.
   *
   * @param entry The history entry to be integrated.
   * @return A copy of this object, with the given history entry integrated.
   */
  public abstract TCSObject withHistoryEntry(ObjectHistory.Entry entry);

  /**
   * Creates a copy of this object, with the given history.
   *
   * @param history The history.
   * @return A copy of this object, with the given history.
   */
  public abstract TCSObject withHistory(ObjectHistory history);

  @Override
  public String toString() {
    return getClass().getSimpleName() + "{name=" + name + '}';
  }

  /**
   * Checks if this object is equal to another one.
   * Two TCSObjects are equal if both their IDs and their runtime
   * classes are equal.
   *
   * @param obj The object to compare this one to.
   * @return true if, and only if, obj is also a
   * TCSObject and both its ID and runtime class equal those of
   * this object.
   */
  @Override
  public boolean equals(Object obj) {
    if (obj instanceof TCSObject) {
      TCSObject other = (TCSObject) obj;
      return this.getName().equals(other.getName()) && this.getClass().equals(other.getClass());
    }
    else {
      return false;
    }
  }

  /**
   * Returns this object's hashcode.
   * A TCSObject's hashcode is calculated by XORing its ID's
   * hashcode and the hashcode of its runtime class's name.
   *
   * @return This object's hashcode.
   */
  @Override
  public int hashCode() {
    return getName().hashCode()
        ^ this.getClass().getName().hashCode();
  }

  /**
   * Returns a new map of this object's properties, with the given property integrated.
   *
   * @param key The key of the property to be changed.
   * @param value The new value of the property, or null, if the property is to be
   * removed.
   * @return A new map of this object's properties, with the given property integrated.
   */
  protected final Map propertiesWith(String key, String value) {
    requireNonNull(key, "key");

    Map result = new HashMap<>(properties);
    if (value == null) {
      result.remove(key);
    }
    else {
      result.put(key, value);
    }
    return result;
  }

  /**
   * Returns a new map with the entries from the given map but all entries with null
   * values removed.
   *
   * @param  The type of the map's keys.
   * @param  The type of the map's values.
   * @param original The original map.
   * @return A new map with the entries from the given map but all entries with null
   * values removed.
   */
  protected static final  Map mapWithoutNullValues(Map original) {
    requireNonNull(original, "original");

    Map result = new HashMap<>();
    for (Map.Entry entry : original.entrySet()) {
      if (entry.getValue() != null) {
        result.put(entry.getKey(), entry.getValue());
      }
    }
    return result;
  }

  /**
   * Returns a new list with the values from the given list but all null values
   * removed.
   *
   * @param  The type of the list's values.
   * @param original The original list.
   * @return A new list with the values from the given list but all null values
   * removed.
   */
  protected static final  List listWithoutNullValues(List original) {
    requireNonNull(original, "original");

    return original.stream()
        .filter(value -> value != null)
        .collect(Collectors.toList());
  }

  /**
   * Returns a new set with the values from the given set but all null values removed.
   *
   * @param  The type of the set's values.
   * @param original The original set.
   * @return A new set with the values from the given set but all null values removed.
   */
  protected static final  Set setWithoutNullValues(Set original) {
    requireNonNull(original, "original");

    return original.stream()
        .filter(value -> value != null)
        .collect(Collectors.toSet());
  }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy