/*
* 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.extension;
import static org.teiid.designer.core.ModelerCore.Util;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.emf.common.util.EMap;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.impl.EStringToStringMapEntryImpl;
import org.teiid.core.designer.ModelerCoreException;
import org.teiid.core.designer.util.CoreArgCheck;
import org.teiid.core.designer.util.CoreStringUtil;
import org.teiid.core.designer.util.I18nUtil;
import org.teiid.designer.core.ModelerCore;
import org.teiid.designer.core.util.ModelContents;
import org.teiid.designer.core.util.ModelResourceContainerFactory;
import org.teiid.designer.core.workspace.ModelResource;
import org.teiid.designer.core.workspace.ModelWorkspaceException;
import org.teiid.designer.extension.definition.ModelExtensionAssistant;
import org.teiid.designer.extension.definition.ModelExtensionDefinition;
import org.teiid.designer.extension.definition.ModelExtensionDefinitionHeader;
import org.teiid.designer.extension.properties.ModelExtensionPropertyDefinition;
import org.teiid.designer.extension.properties.Translation;
import org.teiid.designer.metamodels.core.Annotation;
import org.teiid.designer.metamodels.core.AnnotationContainer;
/**
* Utilities that manage persisting of model extension definitions in model objects.
*/
public class ModelExtensionUtils {
private static final String I18N_PREFIX = I18nUtil.getPropertyPrefix(ModelExtensionUtils.class);
private static final String DEFN_PREFIX = "modelExtensionDefinition"; //$NON-NLS-1$
private static final char DELIM = ':';
private static final String EXTENDED_METACLASS_PREFIX = "extendedMetaclass"; //$NON-NLS-1$
private static final String PROP_DEFN_PREFIX = "propertyDefinition"; //$NON-NLS-1$
private static String constructKey( String prefix,
String id ) {
return prefix + DELIM + id;
}
private static String getKeyId( String prefix,
String key ) {
String prefixStr = prefix + DELIM;
if (key.startsWith(prefixStr)) {
return key.substring(key.indexOf(prefixStr) + prefixStr.length());
}
return ""; //$NON-NLS-1$
}
/**
* Determine if the ModelResource contains a ModelExtensionDefinition with the specified Namespace Prefix.
*
* @param modelResource the model resource being checked (cannot be <code>null</code>)
* @param namespacePrefix the namespace prefix of the model extension definition being looked for (cannot be <code>null</code>
* or empty)
* @return <code>true</code> if the model resource contains the model extension definition with the specified namespace prefix
* @throws Exception if there is a problem accessing the model resource
*/
public static boolean containsModelExtensionDefinition( ModelResource modelResource,
String namespacePrefix ) throws Exception {
// transaction logic not needed as this is a readonly operation
CoreArgCheck.isNotNull(modelResource, "modelResource is null"); //$NON-NLS-1$
return (getDefinitionAnnotation(modelResource, false, namespacePrefix) != null);
}
/**
* Get the ModelExtensionDefinitionHeader for the specified Namespace Prefix for the ModelResource
*
* @param modelResource the model resource being checked (cannot be <code>null</code>)
* @param namespacePrefix the namespace prefix of the model extension definition being looked for (cannot be <code>null</code>
* or empty)
* @return the ModelExtensionDefinitionHeader
* @throws Exception if there is a problem accessing the model resource
*/
public static ModelExtensionDefinitionHeader getModelExtensionDefinitionHeader( ModelResource modelResource,
String namespacePrefix ) throws Exception {
// transaction logic not needed as this is a readonly operation
CoreArgCheck.isNotNull(modelResource, "modelResource is null"); //$NON-NLS-1$
CoreArgCheck.isNotEmpty(namespacePrefix, "namespacePrefix is empty"); //$NON-NLS-1$
ModelExtensionDefinitionHeader header = null;
Annotation defnAnnotation = getDefinitionAnnotation(modelResource, false, namespacePrefix);
if (defnAnnotation != null) {
EMap<String, String> definitionTags = defnAnnotation.getTags();
String metamodelUri = definitionTags.get(DefinitionTagKeys.METAMODEL);
String namespacePrfx = definitionTags.get(DefinitionTagKeys.NAMESPACE_PREFIX);
String namespaceUri = definitionTags.get(DefinitionTagKeys.NAMESPACE_URI);
String description = definitionTags.get(DefinitionTagKeys.DESCRIPTION);
String versionStr = definitionTags.get(DefinitionTagKeys.VERSION);
int version = Integer.parseInt(versionStr);
header = new ModelExtensionDefinitionHeader(namespacePrfx,
namespaceUri,
metamodelUri,
getSupportedModelTypes(modelResource, defnAnnotation),
description,
version);
}
return header;
}
/**
* Reads the annotations from the supplied ModelResource, converting to a ModelExtensionDefinition object
*
* @param assistant the ModelExtensionAssistant
* @param modelResource the model resource (cannot be <code>null</code>)
* @return the ModelExtensionDefinition
* @throws Exception if there is a problem accessing the model resource
*/
public static ModelExtensionDefinition getModelExtensionDefinition( ModelExtensionAssistant assistant,
ModelResource modelResource ) throws Exception {
// transaction logic not needed as this is a readonly operation
CoreArgCheck.isNotNull(assistant, "assistant is null"); //$NON-NLS-1$
CoreArgCheck.isNotNull(modelResource, "modelResource is null"); //$NON-NLS-1$
ModelExtensionDefinition med = null;
String namespacePrefix = assistant.getNamespacePrefix();
// Get the Header info from the modelResource for the supplied namespacePrefix
ModelExtensionDefinitionHeader medHeader = getModelExtensionDefinitionHeader(modelResource, namespacePrefix);
if (medHeader != null) {
// Create a ModelExtensionDefinition
med = assistant.createModelExtensionDefinition(medHeader);
// Get annotation for this namespacePrefix from the modelResource
Annotation defnAnnotation = getDefinitionAnnotation(modelResource, false, namespacePrefix);
if (defnAnnotation != null) {
// Get Tags from the Annotation
EMap<String, String> definitionTags = defnAnnotation.getTags();
// Iterate over Tags, process the extended metaclass tag info
for (Object object : definitionTags.entrySet()) {
if (!(object instanceof EStringToStringMapEntryImpl)) {
throw new Exception(Util.getString(I18N_PREFIX + "modelExtensionDefinitionTagUnexpectedClass", //$NON-NLS-1$
object.getClass()));
}
EStringToStringMapEntryImpl entry = (EStringToStringMapEntryImpl)object;
// Get the Annotation for each extended Metaclass
if (entry.getKey().startsWith(EXTENDED_METACLASS_PREFIX)) {
Annotation metaclassAnnotation = getModelObjectAnnotation(entry, false);
if (metaclassAnnotation == null) {
throw new Exception(Util.getString(I18N_PREFIX + "metaclassAnnotationNotFound", entry.getKey())); //$NON-NLS-1$
}
// Metaclass Name
String metaclassName = getKeyId(EXTENDED_METACLASS_PREFIX, entry.getKey());
// Get Property Definitions for this Metaclass
EMap<String, String> metaclassTags = metaclassAnnotation.getTags();
for (Object metaclassTagObj : metaclassTags.entrySet()) {
if (!(metaclassTagObj instanceof EStringToStringMapEntryImpl)) {
throw new Exception(
Util.getString(I18N_PREFIX + "metaclassEntryUnexpectedClass", metaclassTagObj.getClass())); //$NON-NLS-1$
}
// Find Property Definition Tags
if (((EStringToStringMapEntryImpl)metaclassTagObj).getKey().startsWith(PROP_DEFN_PREFIX)) {
// Get PropertyDefinition Annotation
Annotation propertyDefinitionAnnotation = getModelObjectAnnotation((EStringToStringMapEntryImpl)metaclassTagObj,
false);
if (propertyDefinitionAnnotation == null) {
throw new Exception(
Util.getString(I18N_PREFIX + "propertyDefinitionAnnotationNotFound", ((EStringToStringMapEntryImpl)metaclassTagObj).getKey())); //$NON-NLS-1$
}
// Get ProperyDefinition Values
String simpleId = null;
Set<Translation> displayNames = null;
String runtimeType = null;
String required = Boolean.toString(ModelExtensionPropertyDefinition.REQUIRED_DEFAULT);
String defaultValue = null;
String fixedValue = null;
String advanced = Boolean.toString(ModelExtensionPropertyDefinition.ADVANCED_DEFAULT);
String masked = Boolean.toString(ModelExtensionPropertyDefinition.MASKED_DEFAULT);
String index = Boolean.toString(ModelExtensionPropertyDefinition.INDEX_DEFAULT);
Set<String> allowedValues = null;
Set<Translation> descriptions = null;
// Get Value for each Tag
EMap<String, String> propDefnTags = propertyDefinitionAnnotation.getTags();
for (Object propDefnTagObj : propDefnTags.entrySet()) {
if (!(propDefnTagObj instanceof EStringToStringMapEntryImpl)) {
Util.log(IStatus.ERROR,
Util.getString(I18N_PREFIX + "propertyDefinitionEntryUnexpectedClass", propDefnTagObj.getClass())); //$NON-NLS-1$
}
// Get Tag Key/Value
String key = ((EStringToStringMapEntryImpl)propDefnTagObj).getKey();
String value = ((EStringToStringMapEntryImpl)propDefnTagObj).getValue();
// Id
if (PropertyTagKeys.ID.equals(key)) {
simpleId = value;
// Display Names (multiple for locales)
} else if (PropertyTagKeys.DISPLAY_NAMES.equals(key)) {
displayNames = new HashSet<Translation>();
Annotation displayNamesAnnotation = getModelObjectAnnotation((EStringToStringMapEntryImpl)propDefnTagObj,
false);
EMap<String, String> displayNamesTags = displayNamesAnnotation.getTags();
for (Object temp : displayNamesTags.entrySet()) {
if (!(temp instanceof EStringToStringMapEntryImpl)) {
throw new Exception(Util.getString(I18N_PREFIX
+ "modelExtensionDefinitionTagUnexpectedClass", temp.getClass())); //$NON-NLS-1$
}
EStringToStringMapEntryImpl displayNameEntry = (EStringToStringMapEntryImpl)temp;
String localeTxt = displayNameEntry.getKey();
displayNames.add(new Translation(I18nUtil.parseLocaleString(localeTxt),
displayNameEntry.getValue()));
}
// Descriptions (multiple for locales)
} else if (PropertyTagKeys.DESCRIPTIONS.equals(key)) {
descriptions = new HashSet<Translation>();
Annotation desciptionsAnnotation = getModelObjectAnnotation((EStringToStringMapEntryImpl)propDefnTagObj,
false);
EMap<String, String> descriptionsTags = desciptionsAnnotation.getTags();
for (Object temp : descriptionsTags.entrySet()) {
if (!(temp instanceof EStringToStringMapEntryImpl)) {
throw new Exception(Util.getString(I18N_PREFIX
+ "modelExtensionDefinitionTagUnexpectedClass", temp.getClass())); //$NON-NLS-1$
}
EStringToStringMapEntryImpl descriptionEntry = (EStringToStringMapEntryImpl)temp;
String localeTxt = descriptionEntry.getKey();
descriptions.add(new Translation(I18nUtil.parseLocaleString(localeTxt),
descriptionEntry.getValue()));
}
// Runtime type
} else if (PropertyTagKeys.RUNTIME_TYPE.equals(key)) {
runtimeType = value;
// Required
} else if (PropertyTagKeys.REQUIRED.equals(key)) {
required = value;
// Default Value
} else if (PropertyTagKeys.DEFAULT_VALUE.equals(key)) {
defaultValue = value;
// Fixed Value
} else if (PropertyTagKeys.FIXED_VALUE.equals(key)) {
fixedValue = value;
// Advanced
} else if (PropertyTagKeys.ADVANCED.equals(key)) {
advanced = value;
// Masked
} else if (PropertyTagKeys.MASKED.equals(key)) {
masked = value;
// Index
} else if (PropertyTagKeys.INDEX.equals(key)) {
index = value;
// Allowed Values
} else if (PropertyTagKeys.ALLOWED_VALUES.equals(key)) {
allowedValues = new HashSet<String>();
Annotation allowedValuesAnnotation = getModelObjectAnnotation((EStringToStringMapEntryImpl)propDefnTagObj,
false);
if (allowedValuesAnnotation == null) {
throw new Exception(Util.getString(I18N_PREFIX + "allowedValuesAnnotationNotFound", //$NON-NLS-1$
((EStringToStringMapEntryImpl)propDefnTagObj).getKey()));
}
EMap<String, String> allowedValuesTags = allowedValuesAnnotation.getTags();
for (String allowedValue : allowedValuesTags.keySet()) {
allowedValues.add(allowedValue);
}
}
}
// Create a property definition based on the read in properties, then add it.
ModelExtensionPropertyDefinition propertyDefn = assistant.createPropertyDefinition(simpleId,
runtimeType,
required,
defaultValue,
fixedValue,
advanced,
masked,
index,
allowedValues,
descriptions,
displayNames);
// Add the property definition to the ModelExtensionDefinition
assistant.addPropertyDefinition(metaclassName, propertyDefn);
}
}
}
}
}
}
return med;
}
private static Annotation getAnnotation( ModelResource modelResource,
Annotation parentAnnotation,
String tagId,
String value,
boolean forceCreate ) throws Exception {
// transaction logic not needed as this is not a public method
CoreArgCheck.isNotNull(modelResource, "modelResource is null"); //$NON-NLS-1$
CoreArgCheck.isNotNull(parentAnnotation, "parentAnnotation is null"); //$NON-NLS-1$
CoreArgCheck.isNotNull(tagId, "tagId is null"); //$NON-NLS-1$
CoreArgCheck.isNotNull(value, "value is null"); //$NON-NLS-1$
Annotation annotation = null;
EMap<String, String> tags = parentAnnotation.getTags();
if (!tags.containsKey(tagId)) {
if (forceCreate) {
tags.put(tagId, value);
} else {
return null;
}
}
// find the tag entry associated with the ID
for (Object obj : tags.entrySet()) {
EStringToStringMapEntryImpl entry = (EStringToStringMapEntryImpl)obj;
if (entry.getKey().equals(tagId)) {
annotation = getModelObjectAnnotation(entry, false);
if ((annotation == null) && forceCreate) {
annotation = getModelObjectAnnotation(entry, true);
}
break;
}
}
return annotation;
}
private static Annotation getDefinitionAnnotation( ModelResource modelResource,
boolean forceCreate,
String namespacePrefix ) throws Exception {
// transaction logic not needed as this is not a public method
Annotation annotation = getResourceAnnotation(modelResource, forceCreate);
if (annotation != null) {
String key = constructKey(DEFN_PREFIX, namespacePrefix);
return getAnnotation(modelResource, annotation, key, namespacePrefix, forceCreate);
}
return null;
}
private static Annotation getModelObjectAnnotationImpl( EObject modelObject,
boolean forceCreate ) throws ModelerCoreException {
// transaction logic not needed as this is not a public method
CoreArgCheck.isNotNull(modelObject, "modelObject is null"); //$NON-NLS-1$
return ModelerCore.getModelEditor().getAnnotation(modelObject, forceCreate);
}
/**
* @param modelObject the model object whose annotation is being requested (cannot be <code>null</code>)
* @param forceCreate <code>true</code> if the annotation should be created if it does not exist
* @return the annotation (never <code>null</code>)
* @throws ModelerCoreException
*/
public static Annotation getModelObjectAnnotation( EObject modelObject,
boolean forceCreate ) throws ModelerCoreException {
// transaction needed if forcing creation of objects
if (forceCreate) {
boolean requiredStart = ModelerCore.startTxn(true, true, Util.getString(I18N_PREFIX + "getModelObjectAnnotation"), //$NON-NLS-1$
modelObject);
boolean succeeded = false;
try {
Annotation annotation = getModelObjectAnnotationImpl(modelObject, true);
succeeded = true;
return annotation;
} finally {
// if we started the transaction, commit it.
if (requiredStart) {
if (succeeded) {
ModelerCore.commitTxn();
} else {
ModelerCore.rollbackTxn();
}
}
}
}
return getModelObjectAnnotationImpl(modelObject, false);
}
private static Annotation getModelTypesAnnotation( ModelResource modelResource,
Annotation definitionAnnotation,
boolean forceCreate ) throws Exception {
return getAnnotation(modelResource, definitionAnnotation, DefinitionTagKeys.MODEL_TYPES,
CoreStringUtil.Constants.EMPTY_STRING, forceCreate);
}
private static Annotation getResourceAnnotationImpl( ModelResource modelResource,
boolean forceCreate ) throws ModelWorkspaceException {
// transaction logic not needed as this is not a public method
CoreArgCheck.isNotNull(modelResource, "modelResource"); //$NON-NLS-1$
Annotation annotation = null;
if ((modelResource.getAnnotations() != null) && (modelResource.getModelAnnotation() != null)) {
annotation = modelResource.getAnnotations().getAnnotation(modelResource.getModelAnnotation());
if ((annotation == null) && forceCreate) {
annotation = ModelResourceContainerFactory.createNewAnnotation(modelResource.getModelAnnotation(),
modelResource.getEmfResource());
ModelContents contents = ModelerCore.getModelEditor().getModelContents(modelResource);
AnnotationContainer ac = contents.getAnnotationContainer(true);
if (ac != null) {
annotation.setAnnotationContainer(ac);
}
}
}
return annotation;
}
/**
* Retrieves the tagged resource <code>Annotation</code> object referenced to a <code>ModelResource</code>'s
* <code>ModelAnnotation</code>
*
* @param modelResource the <code>ModelResource</code>. may not be null
* @param forceCreate forces creation of the annotation if it does not exist.
* @return the annotation
* @throws ModelWorkspaceException
*/
public static Annotation getResourceAnnotation( ModelResource modelResource,
boolean forceCreate ) throws ModelWorkspaceException {
// transaction needed if forcing creation of objects
if (forceCreate) {
boolean requiredStart = ModelerCore.startTxn(true, true, Util.getString(I18N_PREFIX + "getResourceAnnotation"), //$NON-NLS-1$
modelResource);
boolean succeeded = false;
try {
Annotation annotation = getResourceAnnotationImpl(modelResource, true);
succeeded = true;
return annotation;
} finally {
// if we started the transaction, commit it.
if (requiredStart) {
if (succeeded) {
ModelerCore.commitTxn();
} else {
ModelerCore.rollbackTxn();
}
}
}
}
return getResourceAnnotationImpl(modelResource, false);
}
private static Set<String> getSupportedModelTypes( ModelResource modelResource, Annotation definitionAnnotation ) throws Exception {
Annotation modelTypesAnnotation = getModelTypesAnnotation(modelResource, definitionAnnotation, false);
if (modelTypesAnnotation != null) {
EMap<String, String> modelTypesTags = modelTypesAnnotation.getTags();
Set<String> modelTypes = new HashSet<String>(modelTypesTags.size());
for (String modelType : modelTypesTags.keySet()) {
modelTypes.add(modelType);
}
return modelTypes;
}
return Collections.emptySet();
}
/**
* @param modelResource the model resource whose supported namespaces is being checked (cannot be <code>null</code>)
* @return the namespace prefixes of all model extension definitions that are persisted in the model resource (never
* <code>null</code>)
* @throws Exception if there is a problem accessing the model resource
*/
public static Collection<String> getSupportedNamespaces( ModelResource modelResource ) throws Exception {
// transaction logic not needed since readonly operation
CoreArgCheck.isNotNull(modelResource, "modelResource is null"); //$NON-NLS-1$
Annotation annotation = getResourceAnnotation(modelResource, false);
if (annotation != null) {
EMap<String, String> tags = annotation.getTags();
Collection<String> namespaces = new ArrayList<String>();
for (String key : tags.keySet()) {
if (key.startsWith(DEFN_PREFIX)) {
// the value is the namespace prefix
namespaces.add(tags.get(key));
}
}
return namespaces;
}
return Collections.emptyList();
}
/**
* @param modelResource the model resource whose namespaces are being checked (cannot be <code>null</code>)
* @param namespace the namespace being verified (cannot be <code>null</code>)
* @return 'true' if the supplied namespace is supported by the modelResource
* @throws Exception if there is a problem accessing the model resource
*/
public static boolean isSupportedNamespace( ModelResource modelResource,
String namespace ) throws Exception {
CoreArgCheck.isNotNull(modelResource, "modelResource is null"); //$NON-NLS-1$
CoreArgCheck.isNotNull(namespace, "namespace is null"); //$NON-NLS-1$
Collection<String> namespaces = getSupportedNamespaces(modelResource);
for (String ns : namespaces) {
if (namespace.equals(ns)) {
return true;
}
}
return false;
}
/**
* @param modelObject the model object being checked (cannot be <code>null</code>)
* @return <code>true</code> if the model object is related to a model extension definition
*/
public static boolean isModelExtensionDefinitionRelated( EObject modelObject ) {
if (modelObject instanceof EStringToStringMapEntryImpl) {
String key = ((EStringToStringMapEntryImpl)modelObject).getKey();
if (key.startsWith(DEFN_PREFIX + DELIM)) {
return true;
}
} else if (modelObject instanceof Annotation) {
return isModelExtensionDefinitionRelated(((Annotation)modelObject).getAnnotatedObject());
}
return false;
}
private static void removeMetaclassAnnotation( ModelResource modelResource,
EStringToStringMapEntryImpl metaclassTag ) throws Exception {
Annotation metaclassAnnotation = getModelObjectAnnotation(metaclassTag, false);
if (metaclassAnnotation == null) {
throw new Exception(Util.getString(I18N_PREFIX + "metaclassAnnotationNotFound", metaclassTag.getKey())); //$NON-NLS-1$
}
EMap<String, String> tags = metaclassAnnotation.getTags();
for (Object object : tags.entrySet()) {
if (!(object instanceof EStringToStringMapEntryImpl)) {
throw new Exception(Util.getString(I18N_PREFIX + "metaclassEntryUnexpectedClass", object.getClass())); //$NON-NLS-1$
}
if (((EStringToStringMapEntryImpl)object).getKey().startsWith(PROP_DEFN_PREFIX)) {
removePropertyDefinition(modelResource, (EStringToStringMapEntryImpl)object);
}
}
// delete annotation
ModelResourceContainerFactory.deleteAnnotation(metaclassAnnotation);
}
/**
* @param modelObject the model object whose property is being removed (cannot be <code>null</code>)
* @param propId the property ID being removed (cannot be <code>null</code> or empty)
* @param deleteModelObjectAnnotation <code>true</code> if the model object annotation should be deleted if there is no other
* remaining information remaining
* @throws Exception if there is a problem accessing the model object's model resource
*/
public static void removeProperty( EObject modelObject,
String propId,
boolean deleteModelObjectAnnotation ) throws Exception {
CoreArgCheck.isNotNull(modelObject, "modelObject is null"); //$NON-NLS-1$
CoreArgCheck.isNotEmpty(propId, "id is empty"); //$NON-NLS-1$
Annotation annotation = getModelObjectAnnotation(modelObject, false);
if (annotation != null) {
annotation.getTags().remove(propId);
if (deleteModelObjectAnnotation && annotation.getTags().isEmpty() && annotation.getDescription() == null) {
ModelResourceContainerFactory.deleteAnnotation(annotation);
}
}
}
private static void removePropertyDefinition( ModelResource modelResource,
EStringToStringMapEntryImpl propertyDefinitionTag ) throws Exception {
Annotation propertyDefinitionAnnotation = getModelObjectAnnotation(propertyDefinitionTag, false);
if (propertyDefinitionAnnotation == null) {
throw new Exception(Util.getString(I18N_PREFIX + "propertyDefinitionAnnotationNotFound", propertyDefinitionTag.getKey())); //$NON-NLS-1$
}
// delete property definition
EMap<String, String> tags = propertyDefinitionAnnotation.getTags();
for (Object object : tags.entrySet()) {
if (!(object instanceof EStringToStringMapEntryImpl)) {
Util.log(IStatus.ERROR, Util.getString(I18N_PREFIX + "propertyDefinitionEntryUnexpectedClass", object.getClass())); //$NON-NLS-1$
}
String key = ((EStringToStringMapEntryImpl)object).getKey();
if (PropertyTagKeys.ALLOWED_VALUES.equals(key)) {
Annotation allowedValuesAnnotation = getModelObjectAnnotation((EStringToStringMapEntryImpl)object, false);
// delete annotation
if (allowedValuesAnnotation != null) {
ModelResourceContainerFactory.deleteAnnotation(allowedValuesAnnotation);
}
}
if (PropertyTagKeys.DISPLAY_NAMES.equals(key)) {
Annotation displayNamesAnnotation = getModelObjectAnnotation((EStringToStringMapEntryImpl)object, false);
// delete annotation
if (displayNamesAnnotation != null) {
ModelResourceContainerFactory.deleteAnnotation(displayNamesAnnotation);
}
}
if (PropertyTagKeys.DESCRIPTIONS.equals(key)) {
Annotation descriptionsAnnotation = getModelObjectAnnotation((EStringToStringMapEntryImpl)object, false);
// delete annotation
if (descriptionsAnnotation != null) {
ModelResourceContainerFactory.deleteAnnotation(descriptionsAnnotation);
}
}
}
// delete annotation
ModelResourceContainerFactory.deleteAnnotation(propertyDefinitionAnnotation);
}
/**
* @param modelResource the model resource where the model extension definition is being removed (cannot be <code>null</code>)
* @param namespacePrefix the namespace prefix of the model extension definition being removed (cannot be <code>null</code> or
* empty)
* @throws Exception if there is a problem accessing the model resource
*/
public static void removeModelExtensionDefinition( ModelResource modelResource,
String namespacePrefix ) throws Exception {
CoreArgCheck.isNotNull(modelResource, "modelResource is null"); //$NON-NLS-1$
Annotation annotation = getResourceAnnotation(modelResource, false);
if (annotation != null) {
Annotation defnAnnotation = getDefinitionAnnotation(modelResource, false, namespacePrefix);
if (defnAnnotation == null) {
throw new Exception(Util.getString(I18N_PREFIX + "defnAnnotationNotFound", namespacePrefix)); //$NON-NLS-1$
}
boolean requiredStart = ModelerCore.startTxn(true, true,
Util.getString(I18N_PREFIX + "removeModelExtensionDefinition"), //$NON-NLS-1$
modelResource);
boolean succeeded = false;
try {
// find model types annotation
Annotation modelTypesAnnotation = getModelTypesAnnotation(modelResource, defnAnnotation, false);
if (modelTypesAnnotation != null) {
ModelResourceContainerFactory.deleteAnnotation(modelTypesAnnotation);
}
// find extended metaclass annotations
EMap<String, String> tags = defnAnnotation.getTags();
for (Object object : tags.entrySet()) {
if (!(object instanceof EStringToStringMapEntryImpl)) {
throw new Exception(Util.getString(I18N_PREFIX + "modelExtensionDefinitionTagUnexpectedClass", //$NON-NLS-1$
object.getClass()));
}
EStringToStringMapEntryImpl entry = (EStringToStringMapEntryImpl)object;
if (entry.getKey().startsWith(EXTENDED_METACLASS_PREFIX)) {
removeMetaclassAnnotation(modelResource, entry);
}
}
// delete annotation
ModelResourceContainerFactory.deleteAnnotation(defnAnnotation);
annotation.getTags().removeKey(constructKey(DEFN_PREFIX, namespacePrefix));
// delete resource annotation if no more tags
if (annotation.getTags().isEmpty()) {
ModelResourceContainerFactory.deleteAnnotation(annotation);
}
succeeded = true;
} finally {
// if we started the transaction, commit it.
if (requiredStart) {
if (succeeded) {
ModelerCore.commitTxn();
} else {
ModelerCore.rollbackTxn();
}
}
}
}
}
/**
* Update the <code>ModelResource</code> annotations, with the supplied <code>ModelExtensionDefinition</code> properties.
*
* @param modelResource the model resource where the model resource definition is being stored (cannot be <code>null</code>)
* @param definition the model extension definition being stored (cannot be <code>null</code>)
* @throws Exception if there is a problem access the model resource
*/
public static void updateModelExtensionDefinition( ModelResource modelResource,
ModelExtensionDefinition definition ) throws Exception {
// TODO need to remove things from model that no longer exist in definition
CoreArgCheck.isNotNull(modelResource, "modelResource is null"); //$NON-NLS-1$
CoreArgCheck.isNotNull(definition, "definition is null"); //$NON-NLS-1$
// update model extension definition properties
String namespacePrefix = definition.getNamespacePrefix();
boolean requiredStart = ModelerCore.startTxn(true, true, Util.getString(I18N_PREFIX + "updateModelExtensionDefinition"), //$NON-NLS-1$
modelResource);
boolean succeeded = false;
try {
Annotation definitionAnnotation = getDefinitionAnnotation(modelResource, true, namespacePrefix);
if (definitionAnnotation == null) {
succeeded = false;
return;
}
EMap<String, String> definitionTags = definitionAnnotation.getTags();
// metamodel URI
String metamodelUri = definition.getMetamodelUri();
if (!CoreStringUtil.equals(definitionTags.get(DefinitionTagKeys.METAMODEL), metamodelUri)) {
definitionTags.put(DefinitionTagKeys.METAMODEL, metamodelUri);
}
// namespace prefix
if (!CoreStringUtil.equals(definitionTags.get(DefinitionTagKeys.NAMESPACE_PREFIX), namespacePrefix)) {
definitionTags.put(DefinitionTagKeys.NAMESPACE_PREFIX, namespacePrefix);
}
// namespace URI
String namespaceUri = definition.getNamespaceUri();
if (!CoreStringUtil.equals(definitionTags.get(DefinitionTagKeys.NAMESPACE_URI), namespaceUri)) {
definitionTags.put(DefinitionTagKeys.NAMESPACE_URI, namespaceUri);
}
// version
int version = definition.getVersion();
if (!CoreStringUtil.equals(definitionTags.get(DefinitionTagKeys.VERSION), Integer.toString(version))) {
definitionTags.put(DefinitionTagKeys.VERSION, Integer.toString(version));
}
// description
String description = definition.getDescription();
if (CoreStringUtil.isEmpty(description)) {
definitionTags.remove(DefinitionTagKeys.DESCRIPTION);
} else if (!CoreStringUtil.equals(definitionTags.get(DefinitionTagKeys.DESCRIPTION), description)) {
definitionTags.put(DefinitionTagKeys.DESCRIPTION, description);
}
// model types
Collection<String> supportedModelTypes = definition.getSupportedModelTypes();
if (supportedModelTypes.isEmpty()) {
definitionTags.remove(DefinitionTagKeys.MODEL_TYPES);
} else {
Annotation modelTypesAnnotation = getModelTypesAnnotation(modelResource, definitionAnnotation, true);
EMap<String, String> modelTypesTags = modelTypesAnnotation.getTags();
modelTypesTags.clear();
// add all supported model types
for (String modelType : supportedModelTypes) {
modelTypesTags.put(modelType, CoreStringUtil.Constants.EMPTY_STRING);
}
}
// Remove metaclass annotations from model if they are not in the MED
String[] medExtendedMetaclasses = definition.getExtendedMetaclasses();
removeUnsupportedMetaclassAnnotations(modelResource, definitionTags, medExtendedMetaclasses);
// properties
for (String extendedMetaclassName : medExtendedMetaclasses) {
String metaclassKey = constructKey(EXTENDED_METACLASS_PREFIX, extendedMetaclassName);
Annotation metaclassAnnotation = getAnnotation(modelResource, definitionAnnotation, metaclassKey,
extendedMetaclassName, true);
// find the tag entry associated with the extended metaclass
for (ModelExtensionPropertyDefinition propDefn : definition.getPropertyDefinitions(extendedMetaclassName)) {
String propKey = constructKey(PROP_DEFN_PREFIX, propDefn.getSimpleId());
Annotation propDefAnnotation = getAnnotation(modelResource, metaclassAnnotation, propKey,
propDefn.getSimpleId(), true);
EMap<String, String> propDefTags = propDefAnnotation.getTags();
String value = null;
// advanced
value = Boolean.toString(propDefn.isAdvanced());
if (!CoreStringUtil.equals(propDefTags.get(PropertyTagKeys.ADVANCED), value)) {
propDefTags.put(PropertyTagKeys.ADVANCED, value);
}
// allowed values
String[] allowedValues = propDefn.getAllowedValues();
// don't save if no allowed values or if a boolean
if ((allowedValues == null) || (allowedValues.length == 0)
|| ModelExtensionPropertyDefinition.Type.BOOLEAN.getRuntimeType().equals(propDefn.getRuntimeType())) {
propDefTags.removeKey(PropertyTagKeys.ALLOWED_VALUES);
} else {
Annotation allowedValuesAnnotation = getAnnotation(modelResource, propDefAnnotation,
PropertyTagKeys.ALLOWED_VALUES,
CoreStringUtil.Constants.EMPTY_STRING, true);
EMap<String, String> allowedValuesTags = allowedValuesAnnotation.getTags();
// add each value
for (String allowedValue : allowedValues) {
allowedValuesTags.put(allowedValue, CoreStringUtil.Constants.EMPTY_STRING);
}
}
DISPLAY_NAMES: {
Set<Translation> displayNames = propDefn.getDisplayNames();
if (!displayNames.isEmpty()) {
Annotation displayNamesAnnotation = getAnnotation(modelResource, propDefAnnotation,
PropertyTagKeys.DISPLAY_NAMES,
CoreStringUtil.Constants.EMPTY_STRING, true);
EMap<String, String> displayNamesTags = displayNamesAnnotation.getTags();
displayNamesTags.clear();
for (Translation translation : displayNames) {
displayNamesTags.put(translation.getLocale().toString(), translation.getTranslation());
}
}
break DISPLAY_NAMES;
}
// default value
value = propDefn.getDefaultValue();
if (!CoreStringUtil.equals(propDefTags.get(PropertyTagKeys.DEFAULT_VALUE), value)) {
if (CoreStringUtil.isEmpty(value)) {
propDefTags.removeKey(PropertyTagKeys.DEFAULT_VALUE);
} else {
propDefTags.put(PropertyTagKeys.DEFAULT_VALUE, value);
}
}
DESCRIPTIONS: {
Set<Translation> descriptions = propDefn.getDescriptions();
if (!descriptions.isEmpty()) {
Annotation descriptionsAnnotation = getAnnotation(modelResource, propDefAnnotation,
PropertyTagKeys.DESCRIPTIONS,
CoreStringUtil.Constants.EMPTY_STRING, true);
EMap<String, String> descriptionsTags = descriptionsAnnotation.getTags();
descriptionsTags.clear();
for (Translation translation : descriptions) {
descriptionsTags.put(translation.getLocale().toString(), translation.getTranslation());
}
}
break DESCRIPTIONS;
}
// id
if (!CoreStringUtil.equals(propDefTags.get(PropertyTagKeys.ID), propDefn.getSimpleId())) {
propDefTags.put(PropertyTagKeys.ID, propDefn.getSimpleId());
}
// index
value = Boolean.toString(propDefn.shouldBeIndexed());
if (!CoreStringUtil.equals(propDefTags.get(PropertyTagKeys.INDEX), value)) {
propDefTags.put(PropertyTagKeys.INDEX, value);
}
// modifiable
value = Boolean.toString(propDefn.isModifiable());
if (!CoreStringUtil.equals(propDefTags.get(PropertyTagKeys.MODIFIABLE), value)) {
propDefTags.put(PropertyTagKeys.MODIFIABLE, value);
}
// masked
value = Boolean.toString(propDefn.isMasked());
if (!CoreStringUtil.equals(propDefTags.get(PropertyTagKeys.MASKED), value)) {
propDefTags.put(PropertyTagKeys.MASKED, value);
}
// required
value = Boolean.toString(propDefn.isRequired());
if (!CoreStringUtil.equals(propDefTags.get(PropertyTagKeys.REQUIRED), value)) {
propDefTags.put(PropertyTagKeys.REQUIRED, value);
}
// runtimeType
value = propDefn.getRuntimeType();
if (!CoreStringUtil.equals(propDefTags.get(PropertyTagKeys.RUNTIME_TYPE), value)) {
propDefTags.put(PropertyTagKeys.RUNTIME_TYPE, value);
}
}
}
succeeded = true;
} finally {
// if we started the transaction, commit it.
if (requiredStart) {
if (succeeded) {
ModelerCore.commitTxn();
} else {
ModelerCore.rollbackTxn();
}
}
}
}
/*
* Remove metaclass annotations from the model that are not included in the supplied MED
* @param modelResc the ModelResource
* @param defnTags the models definition annotation tags
* @param medMetaclasses the array of extended metaclasses in the MED
*/
private static void removeUnsupportedMetaclassAnnotations(ModelResource modelResc, EMap<String, String> defnTags, String[] medMetaclasses) throws Exception {
// Track definition keys for later removal.
List<String> keysToRemove = new ArrayList<String>();
List<String> medMetaclassList = Arrays.asList(medMetaclasses);
// Iterate model's extended metaclass annotations, removing those not in the med.
for (Object object : defnTags.entrySet()) {
if (!(object instanceof EStringToStringMapEntryImpl)) {
throw new Exception(Util.getString(I18N_PREFIX + "modelExtensionDefinitionTagUnexpectedClass", //$NON-NLS-1$
object.getClass()));
}
EStringToStringMapEntryImpl entry = (EStringToStringMapEntryImpl)object;
if (entry.getKey().startsWith(EXTENDED_METACLASS_PREFIX)) {
// Model Extended Metaclass name
String metaclassName = getKeyId(EXTENDED_METACLASS_PREFIX, entry.getKey());
// If Model Extended Metaclass is not in the MED, remove it.
if(!medMetaclassList.contains(metaclassName)) {
removeMetaclassAnnotation(modelResc,entry);
// Track those entries removed
keysToRemove.add(entry.getKey());
}
}
}
// Remove Definition Tag for any removed metaclass annotations
for(String remKey: keysToRemove) {
defnTags.remove(remKey);
}
}
/**
* Don't allow construction.
*/
private ModelExtensionUtils() {
// nothing to do
}
private interface DefinitionTagKeys {
String DESCRIPTION = "description"; //$NON-NLS-1$
String METAMODEL = "metamodel"; //$NON-NLS-1$
String MODEL_TYPES = "modelTypes"; //$NON-NLS-1$
String NAMESPACE_PREFIX = "namespacePrefix"; //$NON-NLS-1$
String NAMESPACE_URI = "namespaceUri"; //$NON-NLS-1$
String VERSION = "version"; //$NON-NLS-1$
}
private interface PropertyTagKeys {
String ADVANCED = "advanced"; //$NON-NLS-1$
String ALLOWED_VALUES = "allowedValues"; //$NON-NLS-1$
String DEFAULT_VALUE = "defaultValue"; //$NON-NLS-1$
String DESCRIPTIONS = "description"; //$NON-NLS-1$
String DISPLAY_NAMES = "displayName"; //$NON-NLS-1$
String ID = "id"; //$NON-NLS-1$
String MASKED = "masked"; //$NON-NLS-1$
String MODIFIABLE = "modifiable"; //$NON-NLS-1$
String REQUIRED = "required"; //$NON-NLS-1$
String RUNTIME_TYPE = "runtimeType"; //$NON-NLS-1$
String FIXED_VALUE = "fixedValue"; //$NON-NLS-1$
String INDEX = "index"; //$NON-NLS-1$
}
}