/*______________________________________________________________________________ * * org.eidola.kernel.Element * * Part of the Eidola Kernel Reference Implementation * See http://eidola.org for oodles of relevant fun! * *______________________________________________________________________________ * * Copyright 1998, 2000-2001 Paul Cantrell * * This program is free software; you can redistribute it and/or modify it under * the terms of the GNU General Public License version 2, as published by the * Free Software Foundation. See the file LICENSE.html for more information. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY, including 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 org.eidola.kernel; import org.eidola.kernel.event.*; import org.eidola.kernel.event.EventListener; import org.eidola.kernel.error.*; import org.eidola.util.Util; import java.util.*; /** A piece of an Eidola program which is owned by another container. Elements can be as large as a Package, or as small as a numeric constant in an expression.
Elements sit in a strict hierarchy -- every Element has exactly one {@link #getOwner() owner}. The chain of owners always reaches up to a {@link Namespace}. All the elements within the namespace have unique {@link #getFullName() full name}s; see {@link NamedElement}.
Structure:
See note on synchronization and concurrent read safety in {@link Container}.
@author Paul Cantrell
@version [Development version]
*/
public abstract class Element
extends Container
{
/** Part of an element.
* @see org.eidola.kernel.event.StructureChanged */
static public final ContainerPart OWNER = new ContainerPart("owner");
/** Creates a new empty element. The new element won't be valid
* until it has an owner. */
public Element()
{
ownerListener = new EventListener()
{
public void handleEvent(Event event)
{ handleOwnerEvent((ContainerEvent) event); }
};
}
//------------------------------------------------------
// Structural properties
//------------------------------------------------------
/** Returns the namespace in which this element lives. */
public Namespace getNamespace()
{ return owner == null ? null : owner.getNamespace(); }
/** Returns this element's owner. */
public Container getOwner()
{ return owner; }
/** Sets this element's owner. This will broadcast a
* {@link StructureChanged} notifying that the {@link #OWNER}
* has changed.
* @throws CyclicOwner If setting this owner would create a
* cycle in the chain of owners. */
public void setOwner(Container newOwner)
throws CyclicOwner
{
if(owner == newOwner)
return;
// Check for cycle in owners
Set visitedElems = new HashSet();
visitedElems.add(this);
for(Container contr = newOwner;
contr instanceof Element;
contr = ((Element) contr).getOwner())
{
if(visitedElems.contains(contr))
throw new CyclicOwner(contr, this + " cannot have a cyclic chain of owners!");
visitedElems.add(contr);
}
// Change owner
Container oldOwner = owner;
Namespace oldNamespace = getNamespace();
owner = newOwner;
Namespace newNamespace = getNamespace();
if(oldOwner != null)
oldOwner.removeListener(ownerListener);
if(newOwner != null)
newOwner.addListener(
ownerListener,
Engine.getInstance().getPropagatorQ());
StructureChanged structEvent = new StructureChanged(this, OWNER);
broadcastEvent(structEvent);
if(oldNamespace != newNamespace)
broadcastEvent(new NamespaceChanged(this, structEvent));
//if(oldScope != newScope)
// broadcastEvent(new ScopeChangedEvent(this, structEvent));
}
/** Returns the list including this container, its owner, its owner's owner,
* etc, up to and including the container's namespace.
* The list goes from the topmost container down.
* Although this is really a derived structure, it is not a member
* of Compilation and is not calculated lazily, because this would
* often lead to the propogation of unreasonable numbers of events. */
public List/*