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

edu.cmu.tetradapp.session.Session Maven / Gradle / Ivy

The newest version!
///////////////////////////////////////////////////////////////////////////////
// For information as to what this class does, see the Javadoc, below.       //
// Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006,       //
// 2007, 2008, 2009, 2010, 2014, 2015, 2022 by Peter Spirtes, Richard        //
// Scheines, Joseph Ramsey, and Clark Glymour.                               //
//                                                                           //
// This program is free software; you can redistribute it and/or modify      //
// it under the terms of the GNU General Public License as published by      //
// the Free Software Foundation; either version 2 of the License, or         //
// (at your option) any later version.                                       //
//                                                                           //
// This program 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 General Public License for more details.                              //
//                                                                           //
// You should have received a copy of the GNU General Public License         //
// along with this program; if not, write to the Free Software               //
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA //
///////////////////////////////////////////////////////////////////////////////

package edu.cmu.tetradapp.session;

import edu.cmu.tetrad.util.TetradSerializable;

import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.Serial;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;

/**
 * 

Stores a directed graph over models of specific types, where the possible * parent relationships between the models are given in the constructors of the model classes themselves. For instance, * if a class Model1 has only this constructor:> 0 public Model1(Model2 x, Model3 y)... *

then if a SessionNode is constructed with Model.class as argument, it will * configure itself as a SessionNode requiring two parents, one capable of implementing models of type Model2 and a * second capable of implementing models of type Model3. If SessionNodes capable of implementing models of types Model2 * and Model3 are available as parents of Model1, a new object of type Model1 can be constructed using them. If Model1 * has more than one constructor, then there is more than one possible set of parents that can be used to construct it. * SessionNodes can also support more than one possible type of model. A SessionNode, for instance, can support the * construction of graphs in general, even if different graphs are implemented using different classes. The SessionNode * can keep track of what its parents are and therefore which of its possible models it's capable of constructing. *

The Session itself keeps track of which nodes are in the session and manages adding and removing nodes. Nodes * that are added to the session must be freshly constructed. This constraint eliminates a number of problems that might * otherwise exist if interconnected SessionNodes were permitted to participate in more than one Session. If the addNode * method is called with a node that is not in the freshly constructed state (either because it was actually just * constructed or because the reset method was just called on the node), an IllegalArgumentException is * thrown.

When a node is removed from a session, all of its connections to other objects are eliminated and its * models destroyed. This has consequences for other objects, since destroying the model of a session node may result in * the destruction of models downstream and the elimination of parent/child relationships between nodes is mutual.> * 0 *

The Session organizes events coming from the nodes in the session so that a listener to the Session receives all * events from the Session. This is convenience service so that listeners do not need to pay attention to all of the * different nodes in the session individually. See SessionEvent for the types of events that are sent.> * 0 *

It is intended for the Session to be serializable. For the Session and * SessionNode classes, this can be checked directly in unit tests. For the various models that the Session can * construct, this has to be tested separately.> 0 * * @author josephramsey * @version $Id: $Id * @see SessionNode * @see SessionListener * @see SessionAdapter * @see SessionEvent */ public final class Session implements TetradSerializable { private static final long serialVersionUID = 23L; /** * The session nodes, stored as a Set of nodes. * * @serial Can't be null. */ private final List nodes = new LinkedList<>(); /** * The name of the session. * * @serial Can't be null. */ private String name; /** * Notes when the model has changed. Should be false at time of deserialization. */ private transient boolean sessionChanged = true; /** * True iff the session is new. Should be false at time of deserialization. */ private transient boolean newSession = true; /** * Convenience class for firing SessionEvents. */ private transient SessionSupport sessionSupport; /** * Handles incoming session events, basically by redirecting to any listeners of this session. */ private transient SessionHandler sessionHandler; //===========================CONSTRUCTORS=============================// /** * Constructs a new session with the given name. (The name cannot be null.) * * @param name a {@link java.lang.String} object */ public Session(String name) { setName(name); } /** * Generates a simple exemplar of this class to test serialization. * * @return a {@link Session} object */ public static Session serializableInstance() { return new Session("X"); } //===========================PUBLIC METHODS===========================// /** * Gets the name. * * @return a {@link java.lang.String} object */ public String getName() { return this.name; } /** * Sets the name. * * @param name a {@link java.lang.String} object */ public void setName(String name) { if (name == null) { throw new NullPointerException("Name must not be null."); } this.name = name; } /** *

Adds the given node to the session, provided the node is in a freshly * created state.> 0 * * @param node a {@link SessionNode} object * @throws java.lang.NullPointerException if the node is null. * @throws java.lang.IllegalArgumentException if the node is not in a freshly created state. There are two ways to * put a SessionNode into a freshly created state. One is to freshly * create it, using one of the constructors. The other was is to call * the * reset method on the SessionNode. * @see SessionNode#isFreshlyCreated * @see SessionNode#resetToFreshlyCreated */ public void addNode(SessionNode node) { if (node == null) { throw new NullPointerException("Node cannot be null."); } if (!node.isFreshlyCreated()) { throw new IllegalArgumentException("Node must be freshly " + "created in order to be added to a session: " + node); } // Causing templates not to work sometimes. Unnecessary. jdramsey 6/5/2015 this.nodes.add(node); node.addSessionListener(getSessionHandler()); getSessionSupport().fireNodeAdded(node); } /** * Adds a list of nodes to the session. Each item in the list must be a SessionNode, and none of them may have a * name that already exists in the session. Upon being added to the session, if any node has a parent that is not in * the list, the parent is removed, the node's model is destroyed, and any models downstream are destroyed as well. * Any children not in the list are removed. Also, any listeners that are not SessionNodes are removed from each * node. * * @param nodes a {@link java.util.List} object */ public void addNodeList(List nodes) { if (nodes == null) { throw new NullPointerException( "The list of nodes must not be " + "null."); } // Verify that all of the nodes are SessionNodes. for (int i = 0; i < nodes.size(); i++) { if (nodes.get(i) == null) { throw new IllegalArgumentException( "The object at index " + i + " is null."); } } // Check to make sure none of the nodes has a name already in the // session. for (SessionNode node : nodes) { if (existsNodeByName(node.getDisplayName())) { throw new IllegalArgumentException( "Attempt to add node to the " + "session with duplicate " + "name: " + node.getDisplayName()); } } // Add the nodes, removing any parents or children not in the list. for (int i = 0; i < nodes.size(); i++) { SessionNode node = nodes.get(i); node.restrictConnectionsToList(nodes); node.restrictListenersToSessionNodes(); this.nodes.add(node); node.addSessionListener(getSessionHandler()); getSessionSupport().fireNodeAdded(node); } } /** *

Removes the given node from the session, removing any connectivity the * node might have to other objects.> 0 * * @param node the SessionNode to be removed. * @throws java.lang.IllegalArgumentException if the specified node is not in the session. * @see SessionNode#resetToFreshlyCreated */ public void removeNode(SessionNode node) { if (this.nodes.contains(node)) { node.resetToFreshlyCreated(); this.nodes.remove(node); node.removeSessionListener(getSessionHandler()); getSessionSupport().fireNodeRemoved(node); } else { throw new IllegalArgumentException( "Node doesn't exist in" + "graph: " + node); } } /** *

Getter for the field nodes.

* * @return the getModel set of session nodes. */ public Set getNodes() { return new HashSet<>(this.nodes); } /** * Removes all nodes. */ public void clearNodes() { // Use the removeNode method to make sure events are fired. Set _nodes = new HashSet<>(this.nodes); for (SessionNode node : _nodes) { removeNode(node); } } /** *

contains.

* * @param node a {@link SessionNode} object * @return a boolean */ public boolean contains(SessionNode node) { return this.nodes.contains(node); } /** * Adds a session listener. * * @param l a {@link SessionListener} object */ public void addSessionListener(SessionListener l) { getSessionSupport().addSessionListener(l); } /** * Removes a session listener. * * @param l a {@link SessionListener} object */ public void removeSessionListener(SessionListener l) { getSessionSupport().removeSessionListener(l); } //=====================PACKAGE PROTECTED METHODS=====================// /** * Indirect reference to session support to avoid saving out any listeners during serialization. */ SessionSupport getSessionSupport() { if (this.sessionSupport == null) { this.sessionSupport = new SessionSupport(this); for (SessionNode node : this.nodes) { node.addSessionListener(getSessionHandler()); } } return this.sessionSupport; } /** * Indirect reference to session handler to avoid saving out listeners during serialization. */ SessionHandler getSessionHandler() { if (this.sessionHandler == null) { this.sessionHandler = new SessionHandler(); } return this.sessionHandler; } //==========================PRIVATE METHODS===========================// /** * @return true iff a node exists in the session with the given name. */ private boolean existsNodeByName(String name) { if (name == null) { return false; } for (SessionNode node : getNodes()) { if (name.equals(node.getDisplayName())) { return true; } } return false; } /** *

isSessionChanged.

* * @return a boolean */ public boolean isSessionChanged() { return this.sessionChanged; } /** *

Setter for the field sessionChanged.

* * @param sessionChanged a boolean */ public void setSessionChanged(boolean sessionChanged) { this.sessionChanged = sessionChanged; } /** *

isNewSession.

* * @return a boolean */ public boolean isNewSession() { return this.newSession; } /** *

Setter for the field newSession.

* * @param newSession a boolean */ public void setNewSession(boolean newSession) { this.newSession = newSession; } //=========================== MEMBER CLASSES =========================// /** *

isEmpty.

* * @return a boolean */ public boolean isEmpty() { return this.nodes.isEmpty(); } /** * Adds semantic checks to the default deserialization method. This method must have the standard signature for a * readObject method, and the body of the method must begin with "s.defaultReadObject();". Other than that, any * semantic checks can be specified and do not need to stay the same from version to version. A readObject method of * this form may be added to any class, even if Tetrad sessions were previously saved out using a version of the * class that didn't include it. (That's what the "s.defaultReadObject();" is for. See J. Bloch, Effective Java, for * help. * * @param s an {@link java.io.ObjectInputStream} object * @throws IOException if any. * @throws ClassNotFoundException if any. */ @Serial private void readObject(ObjectInputStream s) throws IOException, ClassNotFoundException { s.defaultReadObject(); this.sessionChanged = false; this.newSession = false; } /** * Handles SessionEvents. Hides the handling of these from the API. */ private class SessionHandler extends SessionAdapter { /** * This method is called when a node is added. */ public void nodeAdded(SessionEvent event) { getSessionSupport().fireSessionEvent(event); setSessionChanged(true); } /** * This method is called when a node is removed. */ public void nodeRemoved(SessionEvent event) { getSessionSupport().fireSessionEvent(event); setSessionChanged(true); } /** * This method is called when a parent is added. */ public void parentAdded(SessionEvent event) { getSessionSupport().fireSessionEvent(event); setSessionChanged(true); } /** * This method is called when a parent is removed. */ public void parentRemoved(SessionEvent event) { getSessionSupport().fireSessionEvent(event); setSessionChanged(true); } /** * This method is called when a model is created for a node. */ public void modelCreated(SessionEvent event) { getSessionSupport().fireSessionEvent(event); setSessionChanged(true); } /** * This method is called when a model is destroyed for a node. */ public void modelDestroyed(SessionEvent event) { getSessionSupport().fireSessionEvent(event); setSessionChanged(true); } /** * Relays addingEdge events up the chain, without changing their source. */ public void addingEdge(SessionEvent event) { getSessionSupport().fireSessionEvent(event, false); } } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy