/*
* 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.metamodel;
import java.io.File;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.MissingResourceException;
import java.util.Set;
import org.eclipse.emf.common.notify.AdapterFactory;
import org.eclipse.emf.common.util.URI;
import org.eclipse.emf.ecore.EClass;
import org.eclipse.emf.ecore.EClassifier;
import org.eclipse.emf.ecore.EFactory;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.EPackage;
import org.eclipse.emf.ecore.resource.Resource;
import org.eclipse.emf.ecore.resource.ResourceSet;
import org.eclipse.emf.ecore.util.EcoreUtil;
import org.eclipse.emf.edit.provider.IItemLabelProvider;
import org.eclipse.emf.edit.provider.ItemProviderAdapter;
import org.teiid.core.designer.util.CoreArgCheck;
import org.teiid.core.designer.util.CoreStringUtil;
import org.teiid.designer.core.metamodel.aspect.MetamodelAspect;
import org.teiid.designer.metamodels.core.ModelType;
import org.teiid.designer.metamodels.core.extension.XClass;
/**
* The MetaBase Toolkit Registry represents a single naming/directory service through which metamodels can be registered and
* discovered. Each MetamodelRegistry includes a reference to a {@link ResourceSet} used when materializing metamodels as model
* entities. The MetamodelRegistry/ResourceSet pair represents a single meta-level.
*
* @since 8.0
*/
public class MetamodelRegistryImpl implements MetamodelRegistry {
private static final Comparator METAMODEL_ROOT_CLASS_NAME_COMPARATOR = new MetamodelRootClassNameComparator();
private static final EClass[] EMPTY_ECLASS_ARRAY = new EClass[0];
private static final MetamodelRootClass[] EMPTY_METAMODEL_ROOT_CLASS_ARRAY = new MetamodelRootClass[0];
private final Map descriptorByUriMap;
private final Map uriByStringMap;
private final Set uris;
private MetamodelAspectManager aspectMgr;
/**
* @since 5.0
*/
public MetamodelRegistryImpl() {
this.descriptorByUriMap = new HashMap();
this.uriByStringMap = new HashMap();
this.uris = new HashSet();
}
/**
* @see org.teiid.designer.core.metamodel.MetamodelRegistry#containsURI(java.lang.String)
* @since 5.0
*/
@Override
public boolean containsURI( final String nsUriString ) {
if (CoreStringUtil.isEmpty(nsUriString)) {
return false;
}
final URI nsUri = getURI(nsUriString);
if (nsUri == null) {
return false;
}
return containsURI(nsUri);
}
/**
* @see MetamodelRegistry#containsURI(org.eclipse.emf.common.util.URI)
* @since 5.0
*/
@Override
public boolean containsURI( final URI nsUri ) {
if (nsUri == null) {
return false;
}
// Check if the nsUri is the primary namespace URI ...
if (this.uris.contains(nsUri)) {
return true;
}
// Check if the nsUri is an alternate namespace URI
if (this.descriptorByUriMap.keySet().contains(nsUri)) {
return true;
}
return false;
}
/**
* @see org.teiid.designer.core.metamodel.MetamodelRegistry#getMetamodelDescriptor(java.lang.String)
* @since 5.0
*/
@Override
public MetamodelDescriptor getMetamodelDescriptor( final String nsUriString ) {
CoreArgCheck.isNotNull(nsUriString);
CoreArgCheck.isNotZeroLength(nsUriString);
final URI nsUri = getURI(nsUriString);
if (nsUri == null) {
return null;
}
return getMetamodelDescriptor(nsUri);
}
/**
* @see MetamodelRegistry#getMetamodelDescriptor(org.eclipse.emf.common.util.URI)
* @since 5.0
*/
@Override
public MetamodelDescriptor getMetamodelDescriptor( final URI nsUri ) {
CoreArgCheck.isNotNull(nsUri);
return (MetamodelDescriptor)this.descriptorByUriMap.get(nsUri);
}
/**
* @see MetamodelRegistry#getMetamodelDescriptors()
* @since 5.0
*/
@Override
public MetamodelDescriptor[] getMetamodelDescriptors() {
Collection values = new HashSet(this.descriptorByUriMap.values());
return (MetamodelDescriptor[])values.toArray(new MetamodelDescriptor[values.size()]);
}
/**
* {@inheritDoc}
*
* @see MetamodelRegistry#getMetamodelName(String)
*/
@Override
public String getMetamodelName( String nsUriString ) {
MetamodelDescriptor descriptor = getMetamodelDescriptor(nsUriString);
// no descriptor found
if (descriptor == null) {
return null;
}
String name = descriptor.getDisplayName();
if (CoreStringUtil.isEmpty(name)) {
return descriptor.getName();
}
return name;
}
/**
* {@inheritDoc}
*
* @see org.teiid.designer.core.metamodel.MetamodelRegistry#getModelTypeName(java.lang.String)
*/
@Override
public String getModelTypeName( String modelType ) {
CoreArgCheck.isNotEmpty(modelType, "modelType is empty"); //$NON-NLS-1$
for (MetamodelDescriptor descriptor : getMetamodelDescriptors()) {
for (ModelType allowedModelType : descriptor.getAllowableModelTypes()) {
if (allowedModelType.getLiteral().equals(modelType)) {
return allowedModelType.getDisplayName();
}
}
}
return null;
}
/**
* {@inheritDoc}
*
* @see org.teiid.designer.core.metamodel.MetamodelRegistry#getModelTypes(java.lang.String)
*/
@Override
public Set<String> getModelTypes( String nsUriString ) {
MetamodelDescriptor descriptor = getMetamodelDescriptor(nsUriString);
// no descriptor found
if (descriptor == null) {
return Collections.emptySet();
}
ModelType[] modelTypes = descriptor.getAllowableModelTypes();
if (modelTypes.length != 0) {
Set<String> result = new HashSet<String>(modelTypes.length);
for (ModelType modelType : modelTypes) {
result.add(modelType.getLiteral());
}
return result;
}
// should never get here
return Collections.emptySet();
}
/**
* @see MetamodelRegistry#getEPackage(org.eclipse.emf.common.util.URI)
* @since 5.0
*/
@Override
public EPackage getEPackage( final URI nsUri ) {
CoreArgCheck.isNotNull(nsUri);
MetamodelDescriptor descriptor = (MetamodelDescriptor)this.descriptorByUriMap.get(nsUri);
if (descriptor != null) {
return descriptor.getEPackage();
}
return null;
}
/**
* @see MetamodelRegistry#getResource(org.eclipse.emf.common.util.URI)
* @since 5.0
*/
@Override
public Resource getResource( final URI nsUri ) {
CoreArgCheck.isNotNull(nsUri);
MetamodelDescriptor descriptor = (MetamodelDescriptor)this.descriptorByUriMap.get(nsUri);
if (descriptor != null) {
EPackage ePkg = descriptor.getEPackage();
if (ePkg != null) {
return ePkg.eResource();
}
}
return null;
}
/**
* @see MetamodelRegistry#getURI(java.lang.String)
* @since 5.0
*/
@Override
public URI getURI( final String nsUriString ) {
CoreArgCheck.isNotNull(nsUriString);
CoreArgCheck.isNotZeroLength(nsUriString);
return (URI)this.uriByStringMap.get(nsUriString);
}
/**
* @see MetamodelRegistry#getURIs()
* @since 5.0
*/
@Override
public Collection getURIs() {
return this.uris;
}
/**
* @see MetamodelRegistry#register(MetamodelDescriptor)
* @since 5.0
*/
@Override
public URI register( final MetamodelDescriptor descriptor ) {
CoreArgCheck.isNotNull(descriptor);
addDescriptorMappings(descriptor);
return getURI(descriptor.getNamespaceURI());
}
/**
* @see MetamodelRegistry#unregister(org.eclipse.emf.common.util.URI)
* @since 5.0
*/
@Override
public void unregister( final URI nsUri ) {
CoreArgCheck.isNotNull(nsUri);
MetamodelDescriptor descriptor = getMetamodelDescriptor(nsUri);
if (descriptor != null) {
removeDescriptorMappings(descriptor);
}
}
/**
* @see MetamodelRegistry#dispose()
* @since 5.0
*/
@Override
public void dispose() {
MetamodelDescriptor[] descriptors = getMetamodelDescriptors();
for (int i = 0; i != descriptors.length; ++i) {
MetamodelDescriptor d = descriptors[i];
if (d instanceof MetamodelDescriptorImpl) {
((MetamodelDescriptorImpl)d).dispose();
}
}
this.descriptorByUriMap.clear();
this.uriByStringMap.clear();
this.uris.clear();
}
/**
* @see MetamodelRegistry#getAdapterFactory()
* @since 5.0
*/
@Override
public AdapterFactory getAdapterFactory() {
if (this.aspectMgr == null) {
this.aspectMgr = new MetamodelAspectManager(this);
}
return this.aspectMgr.getAdapterFactory();
}
/**
* @see org.teiid.designer.core.metamodel.MetamodelRegistry#getMetamodelAspect(org.eclipse.emf.ecore.EObject,
* java.lang.Class)
* @since 5.0
*/
@Override
public MetamodelAspect getMetamodelAspect( final EObject eObject,
final Class type ) {
CoreArgCheck.isNotNull(eObject);
CoreArgCheck.isNotNull(type);
return getMetamodelAspect(getEClass(eObject), type);
}
/**
* @see MetamodelRegistry#getMetamodelAspect(org.eclipse.emf.ecore.EClass,
* java.lang.Class)
* @since 5.0
*/
@Override
public MetamodelAspect getMetamodelAspect( final EClass eClass,
final Class type ) {
CoreArgCheck.isNotNull(eClass);
CoreArgCheck.isNotNull(type);
if (this.aspectMgr == null) {
this.aspectMgr = new MetamodelAspectManager(this);
}
return this.aspectMgr.getMetamodelAspect(eClass, type);
}
/**
* @see org.teiid.designer.core.metamodel.MetamodelRegistry#getMetaClassLabel(org.eclipse.emf.ecore.EClass)
* @since 5.0
*/
@Override
public String getMetaClassLabel( final EClass eClass ) {
CoreArgCheck.isNotNull(eClass);
final AdapterFactory factory = getAdapterFactory();
final EFactory objectFactory = eClass.getEPackage().getEFactoryInstance();
final EObject instance = objectFactory.create(eClass);
final IItemLabelProvider provider = (IItemLabelProvider)factory.adapt(instance, IItemLabelProvider.class);
if (provider != null && provider instanceof ItemProviderAdapter) {
final ItemProviderAdapter adapter = (ItemProviderAdapter)provider;
try {
final String name = adapter.getString("_UI_" + eClass.getName() + "_type"); //$NON-NLS-1$//$NON-NLS-2$
return name;
} catch (MissingResourceException e) {
// do nothing ...
}
}
return eClass.getName();
}
/**
* @see org.teiid.designer.core.metamodel.MetamodelRegistry#getMetaClassURI(org.eclipse.emf.ecore.EClass)
* @since 5.0
*/
@Override
public String getMetaClassURI( final EClass eClass ) {
CoreArgCheck.isNotNull(eClass);
return EcoreUtil.getURI(eClass).toString();
}
/**
* @see org.teiid.designer.core.metamodel.MetamodelRegistry#getMetaClass(java.lang.String)
* @since 5.0
*/
@Override
public EClass getMetaClass( final String metaClassUriString ) {
CoreArgCheck.isNotNull(metaClassUriString);
CoreArgCheck.isNotZeroLength(metaClassUriString);
URI metaClassUri = URI.createURI(metaClassUriString);
URI nsUri = metaClassUri.trimFragment();
if (nsUri != null) {
EPackage ePackage = getEPackage(nsUri);
if (ePackage != null) {
return (EClass)ePackage.eResource().getEObject(metaClassUri.fragment());
}
}
return null;
}
/**
* @see org.teiid.designer.core.metamodel.MetamodelRegistry#getRootMetaClasses(org.eclipse.emf.common.util.URI)
* @since 5.0
*/
@Override
public EClass[] getRootMetaClasses( final URI nsUri ) {
CoreArgCheck.isNotNull(nsUri);
MetamodelDescriptor d = getMetamodelDescriptor(nsUri);
if (d != null) {
final List metamodelRootClasses = getRootMetaClasses(d);
final List result = new ArrayList(metamodelRootClasses.size());
for (Iterator iter = metamodelRootClasses.iterator(); iter.hasNext();) {
final MetamodelRootClass mrc = (MetamodelRootClass)iter.next();
result.add(mrc.getEClass());
}
return (EClass[])result.toArray(new EClass[result.size()]);
}
return EMPTY_ECLASS_ARRAY;
}
/**
* @see org.teiid.designer.core.metamodel.MetamodelRegistry#getMetamodelRootClasses(org.eclipse.emf.common.util.URI)
* @since 5.0
*/
@Override
public MetamodelRootClass[] getMetamodelRootClasses( URI nsUri ) {
CoreArgCheck.isNotNull(nsUri);
MetamodelDescriptor d = getMetamodelDescriptor(nsUri);
if (d != null) {
final List result = getRootMetaClasses(d);
return (MetamodelRootClass[])result.toArray(new MetamodelRootClass[result.size()]);
}
return EMPTY_METAMODEL_ROOT_CLASS_ARRAY;
}
protected URI createUri( final String uriString ) {
CoreArgCheck.isNotNull(uriString);
CoreArgCheck.isNotZeroLength(uriString);
// Return the existing URI instance if it exists
if (this.uriByStringMap.containsKey(uriString)) {
return (URI)this.uriByStringMap.get(uriString);
}
// Create a new URI instance
URI uri = null;
if ((new File(uriString)).exists()) {
uri = URI.createFileURI(uriString);
} else {
uri = URI.createURI(uriString);
}
return uri;
}
protected EClass getEClass( final EObject eObject ) {
CoreArgCheck.isNotNull(eObject);
if (!(eObject instanceof XClass) && eObject instanceof EClass) {
return (EClass)eObject;
}
return eObject.eClass();
}
protected void addDescriptorMappings( final MetamodelDescriptor descriptor ) {
CoreArgCheck.isNotNull(descriptor);
// Populate the maps with the primary namespace URI information
String nsUriString = descriptor.getNamespaceURI();
URI nsUri = createUri(nsUriString);
this.uriByStringMap.put(nsUriString, nsUri);
this.descriptorByUriMap.put(nsUri, descriptor);
// Only add the primary namespace URI to the set of URIs for the registry
this.uris.add(nsUri);
// If there are alternate namespace URIs for this metamodel then register them also
String[] alternateUris = descriptor.getAlternateNamespaceURIs();
if (alternateUris != null && alternateUris.length > 0) {
for (int i = 0; i != alternateUris.length; ++i) {
nsUriString = alternateUris[i];
nsUri = createUri(nsUriString);
this.uriByStringMap.put(nsUriString, nsUri);
this.descriptorByUriMap.put(nsUri, descriptor);
}
}
}
protected void removeDescriptorMappings( final MetamodelDescriptor descriptor ) {
CoreArgCheck.isNotNull(descriptor);
String nsUriString = descriptor.getNamespaceURI();
URI nsUri = createUri(nsUriString);
this.uris.remove(nsUri);
this.uriByStringMap.remove(nsUriString);
this.descriptorByUriMap.remove(nsUri);
// If there are alternate namespace URIs for this metamodel then register them also
String[] alternateUris = descriptor.getAlternateNamespaceURIs();
if (alternateUris != null && alternateUris.length > 0) {
for (int i = 0; i != alternateUris.length; ++i) {
nsUriString = alternateUris[i];
nsUri = createUri(nsUriString);
this.uriByStringMap.remove(nsUriString);
this.descriptorByUriMap.remove(nsUri);
}
}
}
protected List getRootMetaClasses( final MetamodelDescriptor descriptor ) {
CoreArgCheck.isNotNull(descriptor);
final URI nsUri = getURI(descriptor.getNamespaceURI());
final MetamodelRootClassDescriptor[] rootClasses = descriptor.getRootClassDescriptors();
// If the allowable root classes are defined in the MetamodelDescriptor ...
if (rootClasses != null && rootClasses.length > 0) {
// Create a list of all EClass instances in the metamodel
final List allEClasses = new ArrayList();
final EPackage ePackage = getEPackage(nsUri);
for (Iterator i = ePackage.getEClassifiers().iterator(); i.hasNext();) {
final EClassifier eClassifier = (EClassifier)i.next();
if (eClassifier instanceof EClass) {
final EClass eClass = (EClass)eClassifier;
if (!allEClasses.contains(eClass) && !eClass.isAbstract() && !eClass.isInterface()) {
allEClasses.add(eClass);
}
}
}
// Iterate through the list of all EClass in the metamodel and create
// a list containing only those instances that match the EClass defined
// in the descriptor or implement the interface defined in the descriptor
final Map result = new HashMap(rootClasses.length);
for (Iterator i = allEClasses.iterator(); i.hasNext();) {
final EClass eClass = (EClass)i.next();
// Check the list of EClass instances in the descriptor to see
// if the metamodel EClass instance matches the descriptors
// class or implements the descriptors class interface
for (int j = 0; j < rootClasses.length; j++) {
final Class eClassClass = eClass.getClass();
final Class eClassInstanceClass = eClass.getInstanceClass();
final Class rootClass = rootClasses[j].getExtensionClass();
final int maxOccurs = rootClasses[j].getMaxOccurs();
// Add to the result if the Class instance is the same
if (eClassClass.equals(rootClass) && !result.containsKey(eClass)) {
result.put(eClass, new MetamodelRootClass(eClass, maxOccurs));
break;
}
// Add to the result if the referenced Class instance is the same
else if (eClassInstanceClass != null && eClassInstanceClass.equals(rootClass) && !result.containsKey(eClass)) {
result.put(eClass, new MetamodelRootClass(eClass, maxOccurs));
break;
}
}
}
List listResult = new ArrayList(result.values());
// Sort the list of EClasses before returning it
Collections.sort(listResult, METAMODEL_ROOT_CLASS_NAME_COMPARATOR);
return listResult;
}
return Collections.EMPTY_LIST;
}
static class MetamodelRootClassNameComparator implements Comparator {
@Override
public int compare( Object obj1,
Object obj2 ) {
if (obj1 == null && obj2 == null) {
return 0;
} else if (obj1 == null && obj2 != null) {
return -1;
} else if (obj1 != null && obj2 == null) {
return 1;
}
MetamodelRootClass rootClass1 = (MetamodelRootClass)obj1;
MetamodelRootClass rootClass2 = (MetamodelRootClass)obj2;
EClass eClass1 = rootClass1.getEClass();
EClass eClass2 = rootClass2.getEClass();
String value1 = eClass1.getName();
String value2 = eClass2.getName();
return value1.compareToIgnoreCase(value2);
}
}
}