001package jmri;
002
003/**
004 * Provide a hint to the {@link jmri.InstanceManager} that this object needs
005 * have additional initialization performed after the InstanceManager initially
006 * creates it.  This allows two classes that have circular dependencies on
007 * being able to get the default instance of each other to be managed
008 * successfully.
009 * <p>
010 * More specifically, the constructors or code called by the constructors 
011 * of classes implementing the {@link InstanceManagerAutoDefault} interface 
012 * (i.e. that have the InstanceManager automatically
013 * create their objects) should never ask the InstanceManager for reference to other
014 * automatically-created types. They may ask the InstanceManager for references in their
015 * {@link #initialize()} method, but they can only store those; they can't assume 
016 * that the objects referred to have completed their initialization and are operational.
017 * See the diagram below for why.
018 * <p>
019 * Note: the need to have a class implement this probably is indicative of other
020 * design issues in the implementing class and its dependencies.
021 * <p>
022 * <img src="doc-files/InstanceManagerAutoInitialize-Sequence.png" alt="Initialization sequence UML diagram">
023 *
024 * @author Randall Wood Copyright 2017
025 */
026public interface InstanceManagerAutoInitialize {
027
028    /**
029     * Perform any initialization that occurs after this object has been
030     * constructed and made available by the InstanceManager.
031     */
032    void initialize();
033
034}
035
036/*
037 * @startuml jmri/doc-files/InstanceManagerAutoInitialize-Sequence.png
038 * participant Client
039 * participant InstanceManager
040 * participant ClassA
041 * participant ClassB
042 *
043 * Client -> InstanceManager : getDefault(ClassA)
044 * activate InstanceManager
045 * note over InstanceManager : Doesn't have a ClassA instance
046 *
047 * InstanceManager o-> ClassA : new InstanceManagerAutoDefault#ClassA()
048 * activate ClassA
049 * InstanceManager <-- ClassA : return new ClassA instance
050 * deactivate ClassA
051 * note over InstanceManager : Adds ClassA to list\nso it's available
052 * InstanceManager -> ClassA : InstanceManagerAutoInitialize#initialize()
053 * activate ClassA
054 * note over ClassA : It's safe here to\nask for a ClassB\nreference
055 *
056 * ClassA -> InstanceManager : getDefault(ClassB)
057 * activate InstanceManager
058 * note over InstanceManager : Doesn't have a ClassB instance
059 * InstanceManager o-> ClassB : new InstanceManagerAutoDefault#ClassB()
060 * activate ClassB
061 * InstanceManager <-- ClassB : return new ClassB instance
062 * deactivate ClassB
063 * note over InstanceManager : Adds ClassB to list\nso it's available
064 * InstanceManager -> ClassB : InstanceManagerAutoInitialize#initialize()
065 * activate ClassB
066 *
067 * note over ClassB : It's safe here to\nask for a ClassA\nreference
068 *
069 * ClassB -> InstanceManager : getDefault(ClassA)
070 * activate InstanceManager
071 * note over InstanceManager : Has a ClassA instance,\nthough initialize() is\nnot yet complete
072 * ClassB <-- InstanceManager : return existing ClassA instance
073 * deactivate InstanceManager
074 *
075 * note over ClassB : but not yet to ask\nClassA to operate
076 * InstanceManager <-- ClassB
077 * deactivate ClassB
078 *
079 *
080 *
081 * InstanceManager <-- ClassA
082 * deactivate ClassA
083 *
084 * Client <-- InstanceManager : return new ClassA instance
085 * deactivate InstanceManager
086 *
087 *
088 * @enduml
089 */