/*
* 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.definition;
import static org.teiid.designer.extension.ExtensionPlugin.Util;
import static org.teiid.designer.extension.Messages.invalidDefinitionFileNewVersion;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.concurrent.CopyOnWriteArrayList;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.osgi.util.NLS;
import org.teiid.core.designer.HashCodeUtil;
import org.teiid.core.designer.util.CoreArgCheck;
import org.teiid.core.designer.util.CoreStringUtil;
import org.teiid.designer.extension.definition.ModelExtensionDefinition.PropertyName;
/**
*
*
* @since 8.0
*/
public class ModelExtensionDefinitionHeader {
/**
* The default version number. Value is {@value} .
*/
public static final int DEFAULT_VERSION = 1;
/**
* The definition description (can be <code>null</code> or empty).
*/
private String description;
/**
* The registered property change listeners (never <code>null</code>).
*/
private final CopyOnWriteArrayList<PropertyChangeListener> listeners;
/**
* The metamodel URI that this definition is extended (can be <code>null</code> or empty).
*/
private String metamodelUri;
/**
* A list of applicable model types that the MED can be applied to (can be <code>null</code>). If empty, the MED can be applied
* to any model type.
*/
private Set<String> modelTypes;
/**
* The unique namespace prefix of this definition (can be <code>null</code> or empty).
*/
private String namespacePrefix;
/**
* The unique namespace URI of this definition (can be <code>null</code> or empty).
*/
private String namespaceUri;
/**
* The version number. Defaults to {@value} .
*/
private int version = DEFAULT_VERSION;
public ModelExtensionDefinitionHeader() {
this.listeners = new CopyOnWriteArrayList<PropertyChangeListener>();
}
public ModelExtensionDefinitionHeader( String namespacePrefix,
String namespaceUri,
String metamodelUri,
Set<String> modelTypes,
String description,
int version ) {
this();
this.namespacePrefix = namespacePrefix;
this.namespaceUri = namespaceUri;
this.metamodelUri = metamodelUri;
this.modelTypes = modelTypes;
this.description = description;
this.version = version;
}
/**
* @param listener the listener being added (cannot be <code>null</code>)
* @return <code>true</code> if the listener was successfully added
*/
public boolean addListener( PropertyChangeListener listener ) {
CoreArgCheck.isNotNull(listener, "listener is null"); //$NON-NLS-1$
return this.listeners.addIfAbsent(listener);
}
/**
* @param modelType the model type being added (cannot be <code>null</code> or empty)
* @return <code>true</code> if the model type was added
*/
public boolean addModelType(String modelType) {
CoreArgCheck.isNotEmpty(modelType, "modelType is empty"); //$NON-NLS-1$
if (this.modelTypes == null) {
this.modelTypes = new HashSet<String>(1);
}
boolean added = this.modelTypes.add(modelType);
// alert listeners
if (added) {
notifyChangeListeners(PropertyName.MODEL_TYPES, null, modelType);
}
return added;
}
/**
* @param modelType the model type being added (cannot be <code>null</code> or empty)
* @return <code>true</code> if the model type was added
*/
public void clearModelTypes() {
if (this.modelTypes != null) {
this.modelTypes.clear();
}
}
/**
* {@inheritDoc}
*
* @see java.lang.Object#equals(java.lang.Object)
*/
@Override
public final boolean equals( final Object object ) {
if (this == object) return true;
if (object == null || getClass() != object.getClass()) return false;
final ModelExtensionDefinitionHeader other = (ModelExtensionDefinitionHeader)object;
// check model types
boolean thisEmpty = ((this.modelTypes == null) || this.modelTypes.isEmpty());
boolean otherEmpty = ((other.modelTypes == null) || other.modelTypes.isEmpty());
// make sure both are empty or both are non-empty
if (thisEmpty != otherEmpty) {
return false;
}
// check model type collections contents
if (!thisEmpty) {
// make sure collections are the same size
if (this.modelTypes.size() != other.modelTypes.size()) {
return false;
}
// make sure collections have the same elements
for (String modelType : this.modelTypes) {
if (!other.modelTypes.contains(modelType)) {
return false;
}
}
}
return CoreStringUtil.valuesAreEqual(this.namespacePrefix, other.namespacePrefix)
&& CoreStringUtil.valuesAreEqual(this.namespaceUri, other.namespaceUri)
&& CoreStringUtil.valuesAreEqual(this.metamodelUri, other.metamodelUri)
&& CoreStringUtil.valuesAreEqual(this.description, other.description) && this.version == other.version;
}
/**
* @return description
*/
public String getDescription() {
return description;
}
/**
* @return metamodelUri
*/
public String getMetamodelUri() {
return metamodelUri;
}
/**
* @return namespacePrefix
*/
public String getNamespacePrefix() {
return namespacePrefix;
}
/**
* @return namespaceUri
*/
public String getNamespaceUri() {
return namespaceUri;
}
/**
* @return an unmodifiable collection of supported model types (never <code>null</code> but can be empty)
*/
public Set<String> getSupportedModelTypes() {
if (this.modelTypes == null) {
return Collections.emptySet();
}
return Collections.unmodifiableSet(this.modelTypes);
}
/**
* @return version
*/
public int getVersion() {
return version;
}
/**
* {@inheritDoc}
*
* @see java.lang.Object#hashCode()
*/
@Override
public int hashCode() {
int result = HashCodeUtil.hashCode(0, getVersion());
// string properties
if (getNamespacePrefix() != null && !getNamespacePrefix().isEmpty()) {
result = HashCodeUtil.hashCode(result, getNamespacePrefix());
}
if (getMetamodelUri() != null && !getMetamodelUri().isEmpty()) {
result = HashCodeUtil.hashCode(result, getMetamodelUri());
}
if (getNamespaceUri() != null && !getNamespaceUri().isEmpty()) {
result = HashCodeUtil.hashCode(result, getNamespaceUri());
}
if (getDescription() != null && !getDescription().isEmpty()) {
result = HashCodeUtil.hashCode(result, getDescription());
}
if ((this.modelTypes != null) && !this.modelTypes.isEmpty()) {
if (this.modelTypes.size() == 1) {
result = HashCodeUtil.hashCode(result, this.modelTypes.iterator().next());
} else {
List<String> sortedModelTypes = new ArrayList<String>(this.modelTypes);
Collections.sort(sortedModelTypes);
for (String modelType : sortedModelTypes) {
result = HashCodeUtil.hashCode(result, modelType);
}
}
}
return result;
}
/**
* Broadcasts the property change to all registered listeners.
*
* @param property the property that has been changed (cannot be <code>null</code>)
* @param oldValue the old value (can be <code>null</code>)
* @param newValue (can be <code>null</code>)
*/
private void notifyChangeListeners( final PropertyName property,
final Object oldValue,
final Object newValue ) {
PropertyChangeEvent event = new PropertyChangeEvent(this, property.toString(), oldValue, newValue);
for (final Object listener : this.listeners.toArray()) {
try {
((PropertyChangeListener)listener).propertyChange(event);
} catch (Exception e) {
Util.log(e);
this.listeners.remove(listener);
}
}
}
/**
* @param listener the listener being removed (cannot be <code>null</code>)
* @return <code>true</code> if the listener was successfully removed
*/
public boolean removeListener( PropertyChangeListener listener ) {
CoreArgCheck.isNotNull(listener, "listener is null"); //$NON-NLS-1$
return this.listeners.remove(listener);
}
/**
* @param modelType the model type being removed (cannot be <code>null</code> or empty)
* @return <code>true</code> if the model type was removed
*/
public boolean removeModelType(String modelType) {
CoreArgCheck.isNotEmpty(modelType, "modelType is empty"); //$NON-NLS-1$
boolean removed = false;
if (this.modelTypes != null) {
removed = this.modelTypes.remove(modelType);
}
// alert listeners
if (removed) {
notifyChangeListeners(PropertyName.MODEL_TYPES, modelType, null);
}
return removed;
}
/**
* @param newDescription the new description (can be <code>null</code> or empty)
*/
public void setDescription( String newDescription ) {
String currentValue = getDescription();
if (!CoreStringUtil.equals(currentValue, newDescription)) {
Object oldValue = newDescription;
this.description = newDescription;
// alert listeners
notifyChangeListeners(PropertyName.DESCRIPTION, oldValue, newDescription);
}
}
/**
* @param newMetamodelUri the new metamodel URI (can be <code>null</code> or empty)
*/
public void setMetamodelUri( String newMetamodelUri ) {
String currentValue = getMetamodelUri();
if (!CoreStringUtil.equals(currentValue, newMetamodelUri)) {
Object oldValue = currentValue;
this.metamodelUri = newMetamodelUri;
// alert listeners
notifyChangeListeners(PropertyName.METAMODEL_URI, oldValue, newMetamodelUri);
}
}
/**
* @param newNamespacePrefix the new namespace prefix (can be <code>null</code> or empty)
*/
public void setNamespacePrefix( String newNamespacePrefix ) {
String currentValue = getNamespacePrefix();
if (!CoreStringUtil.equals(currentValue, newNamespacePrefix)) {
Object oldValue = currentValue;
this.namespacePrefix = newNamespacePrefix;
// alert listeners
notifyChangeListeners(PropertyName.NAMESPACE_PREFIX, oldValue, newNamespacePrefix);
}
}
/**
* @param newNamespaceUri the new namespace URI (can be <code>null</code> or empty)
*/
public void setNamespaceUri( String newNamespaceUri ) {
String currentValue = getNamespaceUri();
if (!CoreStringUtil.equals(currentValue, newNamespaceUri)) {
Object oldValue = currentValue;
this.namespaceUri = newNamespaceUri;
// alert listeners
notifyChangeListeners(PropertyName.NAMESPACE_URI, oldValue, newNamespaceUri);
}
}
/**
* If the new version is an invalid version number the version remains unchanged.
*
* @param newVersion the new version
*/
public void setVersion( int newVersion ) {
int currentValue = getVersion();
if (currentValue != newVersion) {
if (newVersion < ModelExtensionDefinitionHeader.DEFAULT_VERSION) {
Util.log(IStatus.ERROR, NLS.bind(invalidDefinitionFileNewVersion, new Object[] { getNamespacePrefix(), newVersion,
currentValue }));
return;
}
Object oldValue = currentValue;
this.version = newVersion;
// alert listeners
notifyChangeListeners(PropertyName.VERSION, oldValue, newVersion);
}
}
/**
* @param modelType the model type being checked (cannot be <code>null</code>)
* @return <code>true</code> if the model type is supported by the MED
*/
public boolean supportsModelType(String modelType) {
CoreArgCheck.isNotEmpty(modelType, "modelType is empty"); //$NON-NLS-1$
// if there are no model types then all model types are supported
if ((this.modelTypes == null) || this.modelTypes.isEmpty()) {
return true;
}
return this.modelTypes.contains(modelType);
}
/**
* {@inheritDoc}
*
* @see java.lang.Object#toString()
*/
@Override
public String toString() {
StringBuilder text = new StringBuilder();
text.append("Model Extension Definition Header: "); //$NON-NLS-1$
text.append("namespacePrefix=").append(getNamespacePrefix()); //$NON-NLS-1$
text.append(", namespaceUri=").append(getNamespaceUri()); //$NON-NLS-1$
text.append(", metamodelUri=").append(getMetamodelUri()); //$NON-NLS-1$
text.append(", version=").append(getVersion()); //$NON-NLS-1$
if (this.modelTypes != null) {
for (String modelType : this.modelTypes) {
text.append(", supported model type=").append(modelType); //$NON-NLS-1$
}
}
return text.toString();
}
}