/*
* 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.extension.ui.model;
import java.util.Collection;
import org.teiid.core.designer.HashCodeUtil;
import org.teiid.core.designer.util.CoreArgCheck;
import org.teiid.designer.extension.definition.ModelExtensionDefinition;
import org.teiid.designer.extension.properties.ModelExtensionPropertyDefinition;
/**
* The <code>MedModelNode</code> wraps attributes and propertes of a {@link ModelExtensionDefinition}.
*/
public class MedModelNode {
private static final MedModelNode[] NO_KIDS = new MedModelNode[0];
/**
* @param medNode the MED node (cannot be <code>null</code> and must wrap the MED)
* @return the MED description node (never <code>null</code>)
*/
public static MedModelNode createDescriptionNode( MedModelNode medNode ) {
CoreArgCheck.isTrue(medNode.isMed(), "node is not a MED node"); //$NON-NLS-1$
return new MedModelNode(medNode, ModelType.DESCRIPTION);
}
/**
* @param med the model extension definition (cannot be <code>null</code>)
* @return the MED node (never <code>null</code>)
*/
public static MedModelNode createMedNode( ModelExtensionDefinition med ) {
CoreArgCheck.isNotNull(med, "MED is null"); //$NON-NLS-1$
return new MedModelNode(med);
}
/**
* @param medNode the MED node (cannot be <code>null</code> and must wrap the MED)
* @param metaclass the extended metaclass name (cannot be <code>null</code> or empty)
* @return the MED metaclass node (never <code>null</code>)
*/
public static MedModelNode createMetaclassNode( MedModelNode medNode,
String metaclass ) {
CoreArgCheck.isTrue(medNode.isMed(), "node is not a MED node"); //$NON-NLS-1$
CoreArgCheck.isNotNull(metaclass, "metaclass is null"); //$NON-NLS-1$
return new MedModelNode(medNode, ModelType.METACLASS, metaclass);
}
/**
* @param medNode the MED node (cannot be <code>null</code> and must wrap the MED)
* @return the MED metamodel URI node (never <code>null</code>)
*/
public static MedModelNode createMetamodelUriNode( MedModelNode medNode ) {
CoreArgCheck.isTrue(medNode.isMed(), "node is not a MED node"); //$NON-NLS-1$
return new MedModelNode(medNode, ModelType.METAMODEL_URI);
}
/**
* @param medNode the MED node (cannot be <code>null</code> and must wrap the MED)
* @return the model types node (never <code>null</code>)
*/
public static MedModelNode createModelTypesNode( MedModelNode medNode ) {
CoreArgCheck.isTrue(medNode.isMed(), "node is not a MED node"); //$NON-NLS-1$
return new MedModelNode(medNode, ModelType.MODEL_TYPES);
}
/**
* @param medNode the MED node (cannot be <code>null</code> and must wrap the MED)
* @return the MED namespace prefix node (never <code>null</code>)
*/
public static MedModelNode createNamespacePrefixNode( MedModelNode medNode ) {
CoreArgCheck.isTrue(medNode.isMed(), "node is not a MED node"); //$NON-NLS-1$
return new MedModelNode(medNode, ModelType.NAMESPACE_PREFIX);
}
/**
* @param medNode the MED node (cannot be <code>null</code> and must wrap the MED)
* @return the MED namespace URI node (never <code>null</code>)
*/
public static MedModelNode createNamespaceUriNode( MedModelNode medNode ) {
CoreArgCheck.isTrue(medNode.isMed(), "node is not a MED node"); //$NON-NLS-1$
return new MedModelNode(medNode, ModelType.NAMESPACE_URI);
}
/**
* @param metaclassNode the MED metaclass node (cannot be <code>null</code> and must wrap the metaclass with the specified
* property)
* @param propDefn the property definition
* @return the MED property definition node (never <code>null</code>)
*/
public static MedModelNode createPropertyNode( MedModelNode metaclassNode,
ModelExtensionPropertyDefinition propDefn ) {
CoreArgCheck.isTrue(metaclassNode.isMetaclass(), "node is not a metaclass node"); //$NON-NLS-1$
CoreArgCheck.isNotNull(propDefn, "propDefn is null"); //$NON-NLS-1$
return new MedModelNode(metaclassNode, ModelType.PROPERTY_DEFINITION, propDefn);
}
/**
* @param medNode the MED node (cannot be <code>null</code> and must wrap the MED)
* @return the MED version node (never <code>null</code>)
*/
public static MedModelNode createVersionNode( MedModelNode medNode ) {
CoreArgCheck.isTrue(medNode.isMed(), "node is not a MED node"); //$NON-NLS-1$
return new MedModelNode(medNode, ModelType.VERSION);
}
private Object data;
private MedModelNode[] kids;
private final MedModelNode parent;
private final ModelType type;
private MedModelNode( MedModelNode parent,
ModelType type ) {
this.parent = parent;
this.type = type;
}
private MedModelNode( MedModelNode parent,
ModelType type,
Object data ) {
this(parent, type);
this.data = data;
}
/**
* @param med the MED being wrapped
*/
private MedModelNode( ModelExtensionDefinition med ) {
this(null, ModelType.MODEL_EXTENSION_DEFINITION, med);
}
/**
* {@inheritDoc}
*
* @see java.lang.Object#equals(java.lang.Object)
*/
@Override
public boolean equals( Object obj ) {
if (this == obj) {
return true;
}
if ((obj == null) || !getClass().equals(obj.getClass())) {
return false;
}
MedModelNode that = (MedModelNode)obj;
if (this.type != that.type) {
return false;
}
if (this.parent == null) {
if (that.parent != null) {
return false;
}
} else if (!this.parent.equals(that.parent)) {
return false;
}
if (this.data == null) {
if (that.data != null) {
return false;
}
} else if (!this.data.equals(that.data)) {
return false;
}
return true;
}
/**
* @return the child nodes (never <code>null</code>)
*/
public MedModelNode[] getChildren() {
if (this.kids == null) {
if (isMed()) {
String[] metaclasses = getMed().getExtendedMetaclasses();
int i = 0;
this.kids = new MedModelNode[6 + metaclasses.length];
this.kids[i++] = createNamespacePrefixNode(this);
this.kids[i++] = createNamespaceUriNode(this);
this.kids[i++] = createMetamodelUriNode(this);
this.kids[i++] = createModelTypesNode(this);
this.kids[i++] = createVersionNode(this);
this.kids[i++] = createDescriptionNode(this);
// create metaclass children
for (String metaclass : metaclasses) {
this.kids[i++] = createMetaclassNode(this, metaclass);
}
} else if (isMetaclass()) {
Collection<ModelExtensionPropertyDefinition> propDefns = getMed().getPropertyDefinitions((String)this.data);
this.kids = new MedModelNode[propDefns.size()];
int i = 0;
for (ModelExtensionPropertyDefinition propDefn : propDefns) {
this.kids[i++] = createPropertyNode(this, propDefn);
}
} else {
this.kids = NO_KIDS;
}
}
return this.kids;
}
/**
* @return the data specific to the node type (can be <code>null</code>)
*/
public Object getData() {
if (isNamespacePrefix()) {
return getMed().getNamespacePrefix();
}
if (isNamespaceUri()) {
return getMed().getNamespaceUri();
}
if (isMetamodelUri()) {
return getMed().getMetamodelUri();
}
if (isModelTypes()) {
return getMed().getSupportedModelTypes();
}
if (isDescription()) {
return getMed().getDescription();
}
if (isVersion()) {
return getMed().getVersion();
}
return this.data;
}
public MedModelNode getDescriptionNode() {
if (isDescription()) {
return this;
}
MedModelNode medNode = getMedNode();
for (MedModelNode kid : medNode.getChildren()) {
if (kid.isDescription()) {
return kid;
}
}
assert false : "description model node not found"; //$NON-NLS-1$
return null;
}
/**
* @return the MED (never <code>null</code>)
*/
public ModelExtensionDefinition getMed() {
MedModelNode medNode = getMedNode();
return (ModelExtensionDefinition)medNode.getData();
}
/**
* @return the MED node (never <code>null</code>)
*/
public MedModelNode getMedNode() {
if (isMed()) {
return this;
}
return getParent().getMedNode();
}
/**
* @return the metaclass name if either a metaclass node or a property definition node (never <code>null</code>)
* @throws IllegalArgumentException if node is not a metaclass node or a property definition node
*/
public String getMetaclass() {
CoreArgCheck.isTrue((isMetaclass() || isPropertyDefinition()), null);
if (isMetaclass()) {
return getData().toString();
}
// must be a property definition node
assert isPropertyDefinition() : "node is not a property definition model node"; //$NON-NLS-1$
return getParent().getMetaclass();
}
public MedModelNode getMetaclassNode( String metaclass ) {
MedModelNode medNode = getMedNode();
for (MedModelNode child : medNode.getChildren()) {
if (child.isMetaclass() && child.getMetaclass().equals(metaclass)) {
return child;
}
}
return null;
}
public MedModelNode getMetamodelUriNode() {
if (isMetamodelUri()) {
return this;
}
MedModelNode medNode = getMedNode();
for (MedModelNode kid : medNode.getChildren()) {
if (kid.isMetamodelUri()) {
return kid;
}
}
assert false : "metamodel URi model node not found"; //$NON-NLS-1$
return null;
}
public MedModelNode getModelTypesNode() {
if (isModelTypes()) {
return this;
}
MedModelNode medNode = getMedNode();
for (MedModelNode kid : medNode.getChildren()) {
if (kid.isModelTypes()) {
return kid;
}
}
assert false : "model types model node not found"; //$NON-NLS-1$
return null;
}
public MedModelNode getNamespacePrefixNode() {
if (isNamespacePrefix()) {
return this;
}
MedModelNode medNode = getMedNode();
for (MedModelNode kid : medNode.getChildren()) {
if (kid.isNamespacePrefix()) {
return kid;
}
}
assert false : "namespace prefix model node not found"; //$NON-NLS-1$
return null;
}
public MedModelNode getNamespaceUriNode() {
if (isNamespaceUri()) {
return this;
}
MedModelNode medNode = getMedNode();
for (MedModelNode kid : medNode.getChildren()) {
if (kid.isNamespaceUri()) {
return kid;
}
}
assert false : "namespace URi model node not found"; //$NON-NLS-1$
return null;
}
/**
* @return the parent node (<code>null</code> if a MED node)
*/
public MedModelNode getParent() {
return this.parent;
}
/**
* @return the property definition if a property definition node (never <code>null</code>)
* @throws IllegalArgumentException if node is not a property definition node
*/
public ModelExtensionPropertyDefinition getPropertyDefinition() {
CoreArgCheck.isTrue(isPropertyDefinition(), null);
return (ModelExtensionPropertyDefinition)getData();
}
public MedModelNode getPropertyDefinitionNode( String metaclass,
ModelExtensionPropertyDefinition propDefn ) {
MedModelNode metaclassNode = getMetaclassNode(metaclass);
if (metaclassNode != null) {
for (MedModelNode propDefnNode : metaclassNode.getChildren()) {
if (propDefn.equals(propDefnNode.getPropertyDefinition())) {
return propDefnNode;
}
}
}
return null;
}
public ModelType getType() {
return this.type;
}
public MedModelNode getVersionNode() {
if (isVersion()) {
return this;
}
MedModelNode medNode = getMedNode();
for (MedModelNode kid : medNode.getChildren()) {
if (kid.isVersion()) {
return kid;
}
}
assert false : "version model node not found"; //$NON-NLS-1$
return null;
}
/**
* {@inheritDoc}
*
* @see java.lang.Object#hashCode()
*/
@Override
public int hashCode() {
int result = HashCodeUtil.hashCode(0, this.type);
result = HashCodeUtil.hashCode(0, this.parent);
return HashCodeUtil.hashCode(result, getData());
}
/**
* @return <code>true</code> if a description node
*/
public boolean isDescription() {
return (this.type == ModelType.DESCRIPTION);
}
/**
* @return <code>true</code> if a MED node
*/
public boolean isMed() {
return (this.type == ModelType.MODEL_EXTENSION_DEFINITION);
}
/**
* @return <code>true</code> if a metaclass node
*/
public boolean isMetaclass() {
return (this.type == ModelType.METACLASS);
}
/**
* @return <code>true</code> if a metamodel URI node
*/
public boolean isMetamodelUri() {
return (this.type == ModelType.METAMODEL_URI);
}
/**
* @return <code>true</code> if a model types node
*/
public boolean isModelTypes() {
return (this.type == ModelType.MODEL_TYPES);
}
/**
* @return <code>true</code> if a namespace prefix node
*/
public boolean isNamespacePrefix() {
return (this.type == ModelType.NAMESPACE_PREFIX);
}
/**
* @return <code>true</code> if a namespace URI node
*/
public boolean isNamespaceUri() {
return (this.type == ModelType.NAMESPACE_URI);
}
/**
* @return <code>true</code> if a property definition node
*/
public boolean isPropertyDefinition() {
return (this.type == ModelType.PROPERTY_DEFINITION);
}
/**
* @return <code>true</code> if a version node
*/
public boolean isVersion() {
return (this.type == ModelType.VERSION);
}
public enum ModelType {
/**
* The description.
*/
DESCRIPTION,
/**
* The metaclass name being extended.
*/
METACLASS,
/**
* The metamodel URI.
*/
METAMODEL_URI,
/**
* A MED.
*/
MODEL_EXTENSION_DEFINITION,
/**
* The supported model types (empty if all model types are supported).
*/
MODEL_TYPES,
/**
* The namespace prefix.
*/
NAMESPACE_PREFIX,
/**
* The namespace URI.
*/
NAMESPACE_URI,
/**
* A property definition.
*/
PROPERTY_DEFINITION,
/**
* The version.
*/
VERSION
}
}