HierarchicalType.java

  1. package org.opentrafficsim.base;

  2. import org.djutils.exceptions.Throw;

  3. /**
  4.  * Super class for types with hierarchical structure. Upper level types without parent can be created in sub classes using a
  5.  * protected constructor without parent.
  6.  * <p>
  7.  * Copyright (c) 2013-2022 Delft University of Technology, PO Box 5, 2600 AA, Delft, the Netherlands. All rights reserved. <br>
  8.  * BSD-style license. See <a href="http://opentrafficsim.org/node/13">OpenTrafficSim License</a>.
  9.  * <p>
  10.  * @version $Revision$, $LastChangedDate$, by $Author$, initial version 30 jun. 2017 <br>
  11.  * @author <a href="http://www.tbm.tudelft.nl/averbraeck">Alexander Verbraeck</a>
  12.  * @author <a href="http://www.tudelft.nl/pknoppers">Peter Knoppers</a>
  13.  * @author <a href="http://www.transport.citg.tudelft.nl">Wouter Schakel</a>
  14.  * @param <T> Self-reference to type.
  15.  */
  16. public abstract class HierarchicalType<T extends HierarchicalType<T>> extends Type<T> implements Identifiable
  17. {

  18.     /** The id of the type to make it identifiable. */
  19.     private final String id;

  20.     /** Parent type. */
  21.     private final T parent;

  22.     /** Cached hash code. */
  23.     private int hashCode;

  24.     /**
  25.      * Constructor for creating the top level types in subclasses.
  26.      * @param id String; The id of the type to make it identifiable.
  27.      * @throws NullPointerException if the id is null
  28.      */
  29.     protected HierarchicalType(final String id) throws NullPointerException
  30.     {
  31.         Throw.whenNull(id, "id cannot be null for hierarchical types");
  32.         this.id = id;
  33.         this.parent = null;
  34.     }

  35.     /**
  36.      * Constructor.
  37.      * @param id String; The id of the type to make it identifiable.
  38.      * @param parent T; parent type
  39.      * @throws NullPointerException if the id is null
  40.      */
  41.     public HierarchicalType(final String id, final T parent) throws NullPointerException
  42.     {
  43.         Throw.whenNull(id, "id cannot be null for hierarchical types");
  44.         this.id = id;
  45.         this.parent = parent;
  46.     }

  47.     /** {@inheritDoc} */
  48.     @Override
  49.     public final String getId()
  50.     {
  51.         return this.id;
  52.     }

  53.     /**
  54.      * @return parent or {@code null} if this is a top level type.
  55.      */
  56.     public final T getParent()
  57.     {
  58.         return this.parent;
  59.     }

  60.     /**
  61.      * Whether this, or any of the parent types, equals the given type.
  62.      * @param type T; type
  63.      * @return whether this, or any of the parent types, equals the given type
  64.      */
  65.     public final boolean isOfType(final T type)
  66.     {
  67.         if (this.equals(type))
  68.         {
  69.             return true;
  70.         }
  71.         if (this.parent != null)
  72.         {
  73.             return this.parent.isOfType(type);
  74.         }
  75.         return false;
  76.     }

  77.     /**
  78.      * Returns the common ancestor of both types.
  79.      * @param type T; other type.
  80.      * @return common ancestor of both types, {@code null} if none
  81.      */
  82.     public final T commonAncestor(final T type)
  83.     {
  84.         T otherType = type;
  85.         while (otherType != null && !isOfType(otherType))
  86.         {
  87.             otherType = otherType.getParent();
  88.         }
  89.         return otherType;
  90.     }

  91.     /** {@inheritDoc} */
  92.     @Override
  93.     @SuppressWarnings("checkstyle:designforextension")
  94.     public int hashCode()
  95.     {
  96.         if (this.hashCode == 0)
  97.         {
  98.             final int prime = 31;
  99.             int result = 1;
  100.             result = prime * result + ((this.id == null) ? 0 : this.id.hashCode());
  101.             this.hashCode = prime * result + ((this.parent == null) ? 0 : this.parent.hashCode());
  102.         }
  103.         return this.hashCode;
  104.     }

  105.     /** {@inheritDoc} */
  106.     @Override
  107.     @SuppressWarnings("checkstyle:designforextension")
  108.     public boolean equals(final Object obj)
  109.     {
  110.         if (this == obj)
  111.         {
  112.             return true;
  113.         }
  114.         if (obj == null)
  115.         {
  116.             return false;
  117.         }
  118.         if (getClass() != obj.getClass())
  119.         {
  120.             return false;
  121.         }
  122.         HierarchicalType<?> other = (HierarchicalType<?>) obj;
  123.         if (this.id == null)
  124.         {
  125.             if (other.id != null)
  126.             {
  127.                 return false;
  128.             }
  129.         }
  130.         else if (!this.id.equals(other.id))
  131.         {
  132.             return false;
  133.         }
  134.         if (this.parent == null)
  135.         {
  136.             if (other.parent != null)
  137.             {
  138.                 return false;
  139.             }
  140.         }
  141.         else if (!this.parent.equals(other.parent))
  142.         {
  143.             return false;
  144.         }
  145.         return true;
  146.     }

  147. }