/*
* JBoss, Home of Professional Open Source.
*
* See the LEGAL.txt file distributed with this work for information regarding copyright ownership and licensing.
*
* See the AUTHORS.txt file distributed with this work for a full listing of individual contributors.
*/
package org.teiid.designer.core.workspace;
import java.util.ArrayList;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.PlatformObject;
import org.teiid.core.designer.HashCodeUtil;
import org.teiid.core.designer.util.CoreArgCheck;
import org.teiid.designer.core.ModelerCore;
/**
* Root of Model Workspace item handle hierarchy.
*
* @see ModelWorkspaceItem
*
* @since 8.0
*/
public abstract class ModelWorkspaceItemImpl extends PlatformObject implements ModelWorkspaceItem {
protected static final int MINIMUM_VALID_TYPE = MODEL_WORKSPACE;
protected static final int MAXIMUM_VALID_TYPE = MAPPING_CLASS_SETS;
/**
* A count to uniquely identify this item in the case that a duplicate named element exists. The occurrence count starts at 1
* (thus the first occurrence is occurrence 1, not occurrence 0).
*/
protected int occurrenceCount = 1;
/**
* State boolean that describes whether this item is currently opening.
*/
protected boolean opening = false;
/**
* State boolean that describes whether this item is currently closing.
*/
protected boolean closing = false;
/**
* This item's type - one of the constants defined in ModelWorkspaceItem.
*/
protected final int fType;
/**
* This item's parent, or <code>null</code> if this item does not have a parent.
*/
protected final ModelWorkspaceItem fParent;
/**
* This item's name, or an empty <code>String</code> if this item does not have a name.
*/
protected final String fName;
protected static final Object NO_INFO = new Object();
/**
* Constructs a handle for a model workspace item of the specified type, with the given parent item and name.
*
* @param type - one of the constants defined in ModelWorkspaceItem
* @exception IllegalArgumentException if the type is not one of the valid model workspace item type constants
*/
protected ModelWorkspaceItemImpl( final int type,
final ModelWorkspaceItem parent,
final String name ) throws IllegalArgumentException {
if (type < MINIMUM_VALID_TYPE || type > MAXIMUM_VALID_TYPE) {
throw new IllegalArgumentException(ModelerCore.Util.getString("element.invalidType")); //$NON-NLS-1$
}
// CoreArgCheck.isNotNull(name); // Should be done in subclasses, not here
// CoreArgCheck.isNotZeroLength(name); // Should be done in subclasses, not here
fType = type;
fParent = parent;
fName = name;
if (fParent != null) {
try {
ModelWorkspaceItemInfo info = fParent.getItemInfo();
info.addChild(this);
} catch (ModelWorkspaceException e) {
ModelerCore.Util.log(IStatus.ERROR,
e,
ModelerCore.Util.getString("ModelWorkspaceItemImpl.Error_trying_to_create_a_modelWorksapceItem_{0}_under_the_parent_{1}_1", name, fParent.getItemName())); //$NON-NLS-1$
}
}
}
/**
* @see org.teiid.designer.core.workspace.ModelWorkspaceItem
*/
@Override
public String getItemName() {
return fName;
}
/**
* @see org.teiid.designer.core.workspace.ModelWorkspaceItem
*/
@Override
public int getItemType() {
return fType;
}
/**
* @see org.teiid.designer.core.workspace.ModelWorkspaceItem
*/
@Override
public ModelWorkspace getModelWorkspace() {
ModelWorkspaceItem current = this;
do {
if (current instanceof ModelWorkspace) return (ModelWorkspace)current;
} while ((current = current.getParent()) != null);
return null;
}
/**
* @see org.teiid.designer.core.workspace.ModelWorkspaceItem
*/
@Override
public ModelProject getModelProject() {
ModelWorkspaceItem current = this;
do {
if (current instanceof ModelProject) return (ModelProject)current;
} while ((current = current.getParent()) != null);
return null;
}
/**
* @see org.teiid.designer.core.workspace.ModelWorkspaceItem
*/
@Override
@SuppressWarnings( "unused" )
public IResource getCorrespondingResource() throws ModelWorkspaceException {
return null;
}
/**
* @see org.teiid.designer.core.workspace.ModelWorkspaceItem
*/
@Override
public Openable getOpenable() {
return this.getOpenableParent();
}
/**
* Return the first instance of IOpenable in the parent hierarchy of this element.
* <p>
* Subclasses that are not IOpenable's must override this method.
*/
public Openable getOpenableParent() {
return (Openable)fParent;
}
/**
* Returns the hash code for this model workspace item. By default, the hash code for an element is a combination of its name
* and parent's hash code. Elements with other requirements must override this method.
*/
@Override
public int hashCode() {
if (fParent == null) {
return super.hashCode();
}
return HashCodeUtil.hashCode(fParent.hashCode(), fName.hashCode());
}
/**
* @see org.teiid.designer.core.workspace.ModelWorkspaceItem
*/
@Override
public boolean isReadOnly() {
return false;
}
/**
* Returns true if this element is an ancestor of the given element, otherwise false.
*
* @param item the item that may be a decendent of this object
* @return true if this item is an ancestor of the supplied item, or false otherwise (including if <code>item</code> is null)
*/
protected boolean isAncestorOf( ModelWorkspaceItem item ) {
if (item == null) {
return false;
}
ModelWorkspaceItem parent = item.getParent();
while (parent != null && !parent.equals(this)) {
parent = parent.getParent();
}
return parent != null;
}
/**
* @see org.teiid.designer.core.workspace.ModelWorkspaceItem
*/
@Override
public ModelWorkspaceItem getParent() {
return fParent;
}
/**
* @see org.teiid.designer.core.workspace.ModelWorkspaceItem
*/
@Override
public ModelWorkspaceItem[] getChildren() throws ModelWorkspaceException {
return ((ModelWorkspaceItemInfo)getItemInfo()).getChildren();
}
/**
* Returns a collection of (immediate) children of this node of the specified type.
*
* @param type - one of constants defined by ModelWorkspaceItem
*/
public ArrayList getChildrenOfType( int type ) throws ModelWorkspaceException {
ModelWorkspaceItem[] children = getChildren();
int size = children.length;
ArrayList list = new ArrayList(size);
for (int i = 0; i < size; ++i) {
ModelWorkspaceItem elt = children[i];
if (elt.getItemType() == type) {
list.add(elt);
}
}
return list;
}
/**
* Returns the first child (immediate) child of this node that has the specified type.
*
* @param type - one of constants defined by ModelWorkspaceItem
* @return the first child found that has the supplied type, or null if there are no children of that type.
*/
public ModelWorkspaceItem getFirstChildrenOfType( int type ) throws ModelWorkspaceException {
ModelWorkspaceItem[] children = getChildren();
int size = children.length;
for (int i = 0; i < size; ++i) {
ModelWorkspaceItem elt = children[i];
if (elt.getItemType() == type) {
return elt;
}
}
return null;
}
/**
* @see org.teiid.designer.core.workspace.ModelWorkspaceItem
*/
@Override
public boolean isStructureKnown() throws ModelWorkspaceException {
return ((ModelWorkspaceItemInfo)getItemInfo()).isStructureKnown();
}
// /**
// * @See org.teiid.designer.core.ModelWorkspaceItem
// */
// public Object getItemInfo() throws ModelWorkspaceException {
// return getItemInfo(false);
// }
/**
* @see org.teiid.designer.core.workspace.ModelWorkspaceItem
*/
@Override
public ModelWorkspaceItemInfo getItemInfo() throws ModelWorkspaceException {
// element info creation is done inside a lock on the ModelWorkspaceManager
ModelWorkspaceManager manager;
synchronized (manager = ModelWorkspaceManager.getModelWorkspaceManager()) {
ModelWorkspaceItemInfo info = manager.getInfo(this);
if (info == null) {
openHierarchy();
info = manager.getInfo(this);
if (info == null) {
throw newNotPresentException();
}
}
return info;
}
}
/**
* Opens this item and all parents that are not already open.
*
* @exception ModelWorkspaceException this item is not present or accessible
*/
protected void openHierarchy() throws ModelWorkspaceException {
if (this instanceof InternalOpenable) {
((InternalOpenable)this).openWhenClosed(null);
} else {
Openable openableParent = getOpenableParent();
if (openableParent != null) {
ModelWorkspaceItemInfo openableParentInfo = (ModelWorkspaceItemInfo)ModelWorkspaceManager.getModelWorkspaceManager().getInfo((ModelWorkspaceItem)openableParent);
if (openableParentInfo == null) {
if (openableParent instanceof InternalOpenable) {
((InternalOpenable)openableParent).openWhenClosed(null);
}
} else {
throw newNotPresentException();
}
}
}
}
// /**
// * Opens this item and all parents that are not already open.
// *
// * @exception ModelWorkspaceException this item is not present or accessible
// */
// protected void openHierarchy() throws ModelWorkspaceException {
// openHierarchy(false);
// }
/**
* This element has just been opened. Do any necessary setup.
*/
protected void opening( Object info ) {
}
/**
* @see Openable
*/
public void close() throws ModelWorkspaceException {
this.closing = true;
boolean wasVerbose = ModelWorkspaceManager.VERBOSE;
try {
Object info = ModelWorkspaceManager.getModelWorkspaceManager().peekAtInfo(this);
if (info != null) {
if (ModelWorkspaceManager.VERBOSE) {
System.out.println("CLOSING Element (" + Thread.currentThread() + "): " + this.toStringWithAncestors()); //$NON-NLS-1$//$NON-NLS-2$
wasVerbose = true;
ModelWorkspaceManager.VERBOSE = false;
}
ModelWorkspaceItem[] children = ((ModelWorkspaceItemInfo)info).getChildren();
for (int i = 0, size = children.length; i < size; ++i) {
ModelWorkspaceItemImpl child = (ModelWorkspaceItemImpl)children[i];
child.close();
}
closing(info);
ModelWorkspaceManager.getModelWorkspaceManager().removeInfo(this);
if (wasVerbose) {
System.out.println("-> Package cache size = " + ModelWorkspaceManager.getModelWorkspaceManager().cache.pkgSize()); //$NON-NLS-1$
}
}
} catch (ModelWorkspaceException e) {
throw e;
} catch (Throwable t) {
ModelerCore.Util.log(t);
} finally {
ModelWorkspaceManager.VERBOSE = wasVerbose;
this.closing = false;
}
}
/**
* This element is being closed. Do any necessary cleanup.
*/
protected void closing( Object info ) {
}
/**
* Removes all cached info from the Model Workspace, including all children, but does not close this element.
*/
protected void removeInfo() {
Object info = ModelWorkspaceManager.getModelWorkspaceManager().peekAtInfo(this);
if (info != null) {
ModelWorkspaceItem[] children = ((ModelWorkspaceItemInfo)info).getChildren();
for (int i = 0, size = children.length; i < size; ++i) {
ModelWorkspaceItemImpl child = (ModelWorkspaceItemImpl)children[i];
child.removeInfo();
}
ModelWorkspaceManager.getModelWorkspaceManager().removeInfo(this);
}
}
/**
* Returns true if this handle represents the same model workspace item as the given handle. By default, two handles represent
* the same element if they are identical or if they represent the same type of element, have equal names, parents, and
* occurrence counts.
* <p>
* If a subclass has other requirements for equality, this method must be overridden.
*
* @see Object#equals
*/
@Override
public boolean equals( Object o ) {
if (this == o) return true;
// Model parent is null
if (fParent == null) return super.equals(o);
if (o instanceof ModelWorkspaceItemImpl) {
ModelWorkspaceItemImpl other = (ModelWorkspaceItemImpl)o;
if (fType != other.fType) return false;
return fName.equals(other.fName) && fParent.equals(other.fParent) && occurrenceCount == other.occurrenceCount;
}
return false;
}
/**
* @see ModelWorkspaceItem
*/
@Override
public boolean exists() {
try {
getItemInfo(); // throws exception if cannot obtain info
return true;
} catch (ModelWorkspaceException e) {
}
return false;
}
/**
* Creates and returns and not present exception for this element.
*/
protected ModelWorkspaceException newNotPresentException() {
return new ModelWorkspaceException(new ModelStatusImpl(ModelStatusConstants.ITEM_DOES_NOT_EXIST, this));
}
/**
* Sets the occurrence count of the handle.
*/
protected void setOccurrenceCount( int count ) {
occurrenceCount = count;
}
protected String tabString( int tab ) {
StringBuffer buffer = new StringBuffer();
for (int i = tab; i > 0; i--)
buffer.append(" "); //$NON-NLS-1$
return buffer.toString();
}
/**
* Debugging purposes
*/
public String toDebugString() {
StringBuffer buffer = new StringBuffer();
this.toStringInfo(0, buffer, NO_INFO);
return buffer.toString();
}
/**
* Debugging purposes
*/
@Override
public String toString() {
StringBuffer buffer = new StringBuffer();
toString(0, buffer);
return buffer.toString();
}
/**
* Debugging purposes
*/
protected void toString( int tab,
StringBuffer buffer ) {
Object info = this.toStringInfo(tab, buffer);
if (tab == 0) {
this.toStringAncestors(buffer);
}
this.toStringChildren(tab, buffer, info);
}
/**
* Debugging purposes
*/
public String toStringWithAncestors() {
StringBuffer buffer = new StringBuffer();
this.toStringInfo(0, buffer, NO_INFO);
this.toStringAncestors(buffer);
return buffer.toString();
}
/**
* Debugging purposes
*/
protected void toStringAncestors( StringBuffer buffer ) {
ModelWorkspaceItemImpl parent = (ModelWorkspaceItemImpl)this.getParent();
if (parent != null && parent.getParent() != null) {
buffer.append(" [in "); //$NON-NLS-1$
parent.toStringInfo(0, buffer, NO_INFO);
parent.toStringAncestors(buffer);
buffer.append("]"); //$NON-NLS-1$
}
}
/**
* Debugging purposes
*/
protected void toStringChildren( int tab,
StringBuffer buffer,
Object info ) {
if (info == null || !(info instanceof ModelWorkspaceItemInfo)) return;
ModelWorkspaceItem[] children = ((ModelWorkspaceItemInfo)info).getChildren();
for (int i = 0; i < children.length; i++) {
buffer.append("\n"); //$NON-NLS-1$
((ModelWorkspaceItemImpl)children[i]).toString(tab + 1, buffer);
}
}
/**
* Debugging purposes
*/
public Object toStringInfo( int tab,
StringBuffer buffer ) {
Object info = ModelWorkspaceManager.getModelWorkspaceManager().peekAtInfo(this);
this.toStringInfo(tab, buffer, info);
return info;
}
/**
* Debugging purposes
*/
protected void toStringInfo( int tab,
StringBuffer buffer,
Object info ) {
buffer.append(this.tabString(tab));
buffer.append(getItemName());
if (info == null) {
buffer.append(" (not open)"); //$NON-NLS-1$
}
}
/* (non-Javadoc)
* @See org.teiid.designer.core.workspace.ModelWorkspaceItem#accept(org.teiid.designer.core.workspace.ModelWorkspaceVisitor, int)
*/
@Override
public void accept( ModelWorkspaceVisitor visitor,
int depth ) throws ModelWorkspaceException {
CoreArgCheck.isNotNull(visitor);
if (depth != DEPTH_INFINITE && depth != DEPTH_ONE && depth != DEPTH_ZERO) {
throw new IllegalArgumentException(ModelerCore.Util.getString("ModelWorkspaceItemImpl.Invalid_visitor_depth")); //$NON-NLS-1$
}
// visit this resource
if (!visitor.visit(this) || depth == DEPTH_ZERO) return;
// visit the children
final int nextDepth = (depth == DEPTH_INFINITE ? DEPTH_INFINITE : DEPTH_ZERO);
final ModelWorkspaceItem[] children = this.getChildren();
for (int i = 0; i < children.length; ++i) {
children[i].accept(visitor, nextDepth);
}
}
/* (non-Javadoc)
* @See org.teiid.designer.core.workspace.ModelWorkspaceItem#getChild(org.eclipse.core.resources.IResource)
*/
@Override
public ModelWorkspaceItem getChild( final IResource resource ) throws ModelWorkspaceException {
CoreArgCheck.isNotNull(resource);
final String resourceName = resource.getName();
return getChild(resourceName);
}
/* (non-Javadoc)
* @See org.teiid.designer.core.workspace.ModelWorkspaceItem#getChild(java.lang.String)
*/
@Override
public ModelWorkspaceItem getChild( final String childName ) throws ModelWorkspaceException {
CoreArgCheck.isNotNull(childName);
final ModelWorkspaceItem[] children = this.getChildren();
for (int j = 0; j < children.length; ++j) {
final ModelWorkspaceItem child = children[j];
if (child.getItemName().equals(childName)) {
return child;
}
}
return null;
}
@Override
public boolean isClosing() {
return this.closing;
}
@Override
public boolean isOpening() {
return this.opening;
}
}