/* * 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.util.ArrayList; import java.util.Collection; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; import org.eclipse.emf.common.notify.Adapter; import org.eclipse.emf.common.notify.AdapterFactory; import org.eclipse.emf.common.notify.Notifier; import org.eclipse.emf.common.util.URI; import org.eclipse.emf.ecore.EClass; import org.eclipse.emf.ecore.EPackage; import org.eclipse.emf.ecore.provider.EcoreItemProviderAdapterFactory; import org.eclipse.emf.ecore.resource.Resource; import org.eclipse.emf.edit.provider.ComposedAdapterFactory; import org.eclipse.emf.edit.provider.resource.ResourceItemProviderAdapterFactory; import org.teiid.core.designer.util.CoreArgCheck; import org.teiid.designer.core.ModelerCore; import org.teiid.designer.core.metamodel.aspect.DependencyAspect; import org.teiid.designer.core.metamodel.aspect.FeatureConstraintAspect; import org.teiid.designer.core.metamodel.aspect.ImportsAspect; import org.teiid.designer.core.metamodel.aspect.MetamodelAspect; import org.teiid.designer.core.metamodel.aspect.MetamodelAspectFactory; import org.teiid.designer.core.metamodel.aspect.MetamodelEntity; import org.teiid.designer.core.metamodel.aspect.ValidationAspect; import org.teiid.designer.core.metamodel.aspect.relationship.RelationshipMetamodelAspect; import org.teiid.designer.core.metamodel.aspect.sql.SqlAspect; import org.teiid.designer.core.metamodel.aspect.uml.UmlDiagramAspect; /** * @since 8.0 */ public class MetamodelAspectManager { // Mappings between the aspect type and the plugin.xml extension ID for the MetamodelAspectFactory private static final Map ASPECT_INTERFACE_TO_EXTENSION_ID = new HashMap(7); static { ASPECT_INTERFACE_TO_EXTENSION_ID.put(SqlAspect.class, ModelerCore.EXTENSION_POINT.SQL_ASPECT.ID); ASPECT_INTERFACE_TO_EXTENSION_ID.put(UmlDiagramAspect.class, ModelerCore.EXTENSION_POINT.UML_DIAGRAM_ASPECT.ID); ASPECT_INTERFACE_TO_EXTENSION_ID.put(ValidationAspect.class, ModelerCore.EXTENSION_POINT.VALIDATION_ASPECT.ID); ASPECT_INTERFACE_TO_EXTENSION_ID.put(DependencyAspect.class, ModelerCore.EXTENSION_POINT.DEPENDENCY_ASPECT.ID); ASPECT_INTERFACE_TO_EXTENSION_ID.put(FeatureConstraintAspect.class, ModelerCore.EXTENSION_POINT.FEATURE_CONSTRAINT_ASPECT.ID); ASPECT_INTERFACE_TO_EXTENSION_ID.put(ImportsAspect.class, ModelerCore.EXTENSION_POINT.IMPORT_ASPECT.ID); ASPECT_INTERFACE_TO_EXTENSION_ID.put(RelationshipMetamodelAspect.class, ModelerCore.EXTENSION_POINT.RELATIONSHIP_ASPECT.ID); } private MetamodelRegistry registry; private Map metamodelEntityMap; // keyed on EClass private ComposedAdapterFactory composedAdapterFactory; // ================================================================================== // C O N S T R U C T O R S // ================================================================================== /** * @since 5.0 */ public MetamodelAspectManager( final MetamodelRegistry theRegistry ) { CoreArgCheck.isNotNull(theRegistry); this.registry = theRegistry; this.metamodelEntityMap = new HashMap(); // Ensure that all the metamodels in the registry are initialized initializeRegistry(this.registry); } // ================================================================================== // P U B L I C M E T H O D S // ================================================================================== /** * Return the {@link ComposedAdapterFactory} reference that is aware of all loaded metamodels. If no metamodels are yet loaded * then null is returned. */ public AdapterFactory getAdapterFactory() { // Create the inital ComposedAdapterFactory instance if it does not yet exist if (this.composedAdapterFactory == null) { this.composedAdapterFactory = new MetamodelComposedAdapterFactory(new ResourceItemProviderAdapterFactory()); // Add any additional metamodel AdapterFactory instances to the ComposedAdapterFactory final MetamodelDescriptor[] descriptors = getRegistry().getMetamodelDescriptors(); for (int i = 0; i < descriptors.length; i++) { final MetamodelDescriptor d = descriptors[i]; addAdapterFactories(this.composedAdapterFactory, d); } } return composedAdapterFactory; } /** * Return the associated MetamodelAspect for the EClass and aspect type. The type is the key used to look up the appropriate * factory and MetamodelAspect. The type is expected to be one of the following: * <p> * <li>org.teiid.designer.core.metamodel.aspect.SqlAspect * <li>org.teiid.designer.core.metamodel.aspect.UmlDiagramAspect * <li>org.teiid.designer.core.metamodel.aspect.ValidationAspect * <li>org.teiid.designer.core.metamodel.aspect.DependencyAspect * <li>org.teiid.designer.core.metamodel.aspect.FeatureConstraintAspect * <li>org.teiid.designer.core.metamodel.aspect.ImportsAspect * <li>org.teiid.designer.core.metamodel.aspect.RelationshipMetamodelAspect * </p> * * @param eClass object whose MetamodelAspect is requested; may not be null * @param type the key indicating the type of MetamodelAspect required; may not be null * @return associated MetamodelAspect */ public MetamodelAspect getMetamodelAspect( final EClass eClass, final Class type ) { CoreArgCheck.isNotNull(eClass); CoreArgCheck.isNotNull(type); MetamodelEntity entity = getMetamodelEntity(eClass); if (entity != null) { String extensionID = (String)ASPECT_INTERFACE_TO_EXTENSION_ID.get(type); if (extensionID == null) { final String msg = ModelerCore.Util.getString("MetamodelAspectManager.Class_does_not_match_any_metamodel_aspect_ID", type.getName()); //$NON-NLS-1$ throw new IllegalArgumentException(msg); } return entity.getMetamodelAspect(extensionID); } return null; } /** * Return the associated MetamodelAspect for the EClass and aspect type identifier. The identifier is the key used to look up * the appropriate factory and MetamodelAspect. The identifier is expected to be one of the following: * <p> * <li>ModelerCore.EXTENSION_POINT.SQL_ASPECT.ID * <li>ModelerCore.EXTENSION_POINT.UML_DIAGRAM_ASPECT.ID * <li>ModelerCore.EXTENSION_POINT.VALIDATION_ASPECT.ID * <li>ModelerCore.EXTENSION_POINT.DEPENDENCY_ASPECT.ID * <li>ModelerCore.EXTENSION_POINT.FEATURE_CONSTRAINT_ASPECT.ID * <li>ModelerCore.EXTENSION_POINT.IMPORT_ASPECT.ID * <li>ModelerCore.EXTENSION_POINT.RELATIONSHIP_ASPECT.ID * </p> * * @param eClass object whose MetamodelAspect is requested; may not be null * @param extensionID the key indicating the type of MetamodelAspectFactory to return; may not be null * @return the MetamodelAspect */ public MetamodelAspect getMetamodelAspect( final EClass eClass, final String extensionID ) { CoreArgCheck.isNotNull(eClass); CoreArgCheck.isNotNull(extensionID); CoreArgCheck.isNotZeroLength(extensionID); MetamodelEntity entity = getMetamodelEntity(eClass); if (entity != null) { return entity.getMetamodelAspect(extensionID); } return null; } // ================================================================================== // P R O T E C T E D M E T H O D S // ================================================================================== protected void initializeRegistry( final MetamodelRegistry registry ) { CoreArgCheck.isNotNull(registry); try { final MetamodelDescriptor[] descriptors = getRegistry().getMetamodelDescriptors(); for (int i = 0; i != descriptors.length; ++i) { MetamodelDescriptor d = descriptors[i]; registry.register(d); URI nsUri = registry.getURI(d.getNamespaceURI()); CoreArgCheck.isNotNull(nsUri); EPackage ePkg = registry.getEPackage(nsUri); CoreArgCheck.isNotNull(ePkg); } } catch (Throwable e) { ModelerCore.Util.log(e); } } protected void addAdapterFactories( final ComposedAdapterFactory composedFactory, final MetamodelDescriptor descriptor ) { CoreArgCheck.isNotNull(composedFactory); CoreArgCheck.isNotNull(descriptor); AdapterFactory[] factories = descriptor.getAdapterFactories(); for (int i = 0; i < factories.length; i++) { final AdapterFactory factory = factories[i]; if (factory != null) { composedFactory.addAdapterFactory(factory); } } } protected MetamodelAspectFactory[] getAspectFactories( final EClass eClass ) { CoreArgCheck.isNotNull(eClass); // Check that this metamodel is known by the registry final URI metamodelURI = getMetamodelURI(eClass); checkIsRegisteredMetamodel(metamodelURI); // Retrieve the aspect factories from the metamodel descriptor final MetamodelDescriptor d = getRegistry().getMetamodelDescriptor(metamodelURI); return d.getAspectFactories(); } protected MetamodelEntity getMetamodelEntity( final EClass eClass ) { CoreArgCheck.isNotNull(eClass); // If this EClass is not contained within one of our suppored metamodels ... if (!isSupportedMetamodel(eClass)) { return null; } // Check that this metamodel is known by the registry final URI metamodelURI = getMetamodelURI(eClass); checkIsRegisteredMetamodel(metamodelURI); if (!getMetamodelEntityMap().containsKey(eClass)) { getMetamodelEntityMap().put(eClass, createMetamodelEntity(eClass)); } return (MetamodelEntity)getMetamodelEntityMap().get(eClass); } protected MetamodelEntity createMetamodelEntity( final EClass eClass ) { CoreArgCheck.isNotNull(eClass); final URI metamodelURI = getMetamodelURI(eClass); final MetamodelEntityImpl entity = new MetamodelEntityImpl(metamodelURI, eClass); // Create any MetamodelAspect instances associated with this EClass final MetamodelAspectFactory[] factories = getAspectFactories(eClass); for (int i = 0; i < factories.length; i++) { final MetamodelAspectFactory factory = factories[i]; try { final MetamodelAspect aspect = factory.create(eClass, entity); if (aspect != null) { entity.addMetamodelAspect(aspect.getID(), aspect); } } catch (IllegalArgumentException e) { // result if no aspect can be created from this entity } } return entity; } protected URI getMetamodelURI( final EClass eClass ) { CoreArgCheck.isNotNull(eClass); return URI.createURI(eClass.getEPackage().getNsURI()); } protected boolean isSupportedMetamodel( final EClass eClass ) { CoreArgCheck.isNotNull(eClass); final Resource resource = eClass.eResource(); if (resource != null) { final URI metamodelURI = resource.getURI(); if (metamodelURI != null && getRegistry().containsURI(metamodelURI)) { return true; } } return false; } protected void checkIsRegisteredMetamodel( final URI metamodelURI ) { if (!getRegistry().containsURI(metamodelURI)) { final String msg = ModelerCore.Util.getString("MetamodelAspectManager.Metamodel_does_not_exist_in_registry", metamodelURI); //$NON-NLS-1$ throw new IllegalArgumentException(msg); } } protected MetamodelRegistry getRegistry() { return this.registry; } protected Map getMetamodelEntityMap() { return this.metamodelEntityMap; } // ================================================================================== // I N N E R C L A S S // ================================================================================== protected static class MetamodelComposedAdapterFactory extends ComposedAdapterFactory { private static final String UML_ADAPTER_FACTORY_CLASS_NAME = "org.teiid.designer.metamodels.uml2.provider.Uml2ItemProviderAdapterFactory"; //$NON-NLS-1$ private EcoreItemProviderAdapterFactory ecoreAdapter; public MetamodelComposedAdapterFactory( final AdapterFactory delegateFactory ) { super(delegateFactory); } @Override public AdapterFactory getFactoryForTypes( Collection types ) { AdapterFactory result = super.getFactoryForTypes(types); if (result != null) { return result; } return super.getFactoryForTypes(types); } /** * @see org.eclipse.emf.edit.provider.ComposedAdapterFactory#adapt(org.eclipse.emf.common.notify.Notifier, * java.lang.Object) */ @Override public Adapter adapt( Notifier target, Object type ) { Adapter adapter = super.adapt(target, type); if (adapter == null && ecoreAdapter != null) { // See if the ECore adapter works ... adapter = ecoreAdapter.adapt(target, type); } return adapter; } /** * @see org.eclipse.emf.edit.provider.ComposedAdapterFactory#addAdapterFactory(org.eclipse.emf.common.notify.AdapterFactory) */ @Override public void addAdapterFactory( AdapterFactory adapterFactory ) { if (adapterFactory == null) { return; } AdapterFactory ecoreAdapterFactory = null; AdapterFactory umlAdapterFactory = null; // Make a copy so we can iterate without fear of co-modification List tempAdapterFactories = new ArrayList(this.adapterFactories); for (Iterator i = tempAdapterFactories.iterator(); i.hasNext();) { final AdapterFactory af = (AdapterFactory)i.next(); // If an AdapterFactory already exists then return if (af != null && af.getClass().equals(adapterFactory.getClass())) { return; } // If we've found the Uml adapter factory, save its reference if (UML_ADAPTER_FACTORY_CLASS_NAME.equals(af.getClass().getName())) { umlAdapterFactory = af; } // If we've found the ECore adapter factory, save its reference else if (af.getClass().equals(EcoreItemProviderAdapterFactory.class)) { ecoreAdapterFactory = af; } } super.addAdapterFactory(adapterFactory); // If we found the Uml adapter factory, remove it then add it back in if (umlAdapterFactory != null) { this.adapterFactories.remove(umlAdapterFactory); super.addAdapterFactory(umlAdapterFactory); } // If we found the ECore adapter factory, remove it then add it back in - always at the end (because it can adapt // anything) if (ecoreAdapterFactory != null) { this.adapterFactories.remove(ecoreAdapterFactory); super.addAdapterFactory(ecoreAdapterFactory); ecoreAdapter = (EcoreItemProviderAdapterFactory)ecoreAdapterFactory; } } } }