/* * 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.mapping.factory; import java.util.HashMap; import java.util.Map; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IConfigurationElement; import org.eclipse.core.runtime.IExtension; import org.eclipse.core.runtime.IExtensionPoint; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.Platform; import org.eclipse.emf.ecore.EObject; import org.eclipse.emf.ecore.resource.Resource; import org.teiid.core.designer.util.CoreArgCheck; import org.teiid.core.designer.util.I18nUtil; import org.teiid.designer.core.ModelerCore; import org.teiid.designer.core.container.Container; import org.teiid.designer.core.resource.EmfResource; import org.teiid.designer.mapping.PluginConstants; import org.teiid.designer.metamodels.core.ModelAnnotation; /** * ModelMapperFactory * * @since 8.0 */ public class ModelMapperFactory implements PluginConstants, PluginConstants.ExtensionPoints.ModelMapper { // ///////////////////////////////////////////////////////////////////////////////////////////// // CONSTANTS // ///////////////////////////////////////////////////////////////////////////////////////////// /** Used in logging debug messages. */ private static final Class CLASS = ModelMapperFactory.class; /** Localization prefix found in properties file key words. */ private static final String PREFIX = I18nUtil.getPropertyPrefix(CLASS); // ///////////////////////////////////////////////////////////////////////////////////////////// // INITIALIZER // ///////////////////////////////////////////////////////////////////////////////////////////// static { buildMapperMaps(); } // ///////////////////////////////////////////////////////////////////////////////////////////// // FIELDS // ///////////////////////////////////////////////////////////////////////////////////////////// /** Map used to create a new instance of a Mapper upon request. */ private static Map uriConfigElementMap; // key=metamodel URI; value=IConfigurationElement /** Map used to see if a known Mapper has a tree root of a certain type. */ private static Map uriMapperMap; // key=metamodel URI; value=ITreeToRelationalMapper /** Don't allow construction. */ private ModelMapperFactory() { } private static void buildMapperMaps() { uriConfigElementMap = new HashMap(); uriMapperMap = new HashMap(); // get the ModelObjectActionContributor extension point from the plugin class IExtensionPoint extensionPoint = Platform.getExtensionRegistry().getExtensionPoint(PLUGIN_ID, ID); // get the all extensions to the ModelObjectActionContributor extension point IExtension[] extensions = extensionPoint.getExtensions(); if (extensions.length > 0) { // for each extension get their contributor for (int i = 0; i < extensions.length; i++) { IConfigurationElement[] elements = extensions[i].getConfigurationElements(); Object extension = null; String metamodelUri = null; for (int j = 0; j < elements.length; j++) { try { extension = elements[j].createExecutableExtension(CLASSNAME); if (extension instanceof ITreeToRelationalMapper) { metamodelUri = elements[j].getAttribute(METAMODEL_URI); if ((metamodelUri != null) && (metamodelUri.length() > 0)) { uriMapperMap.put(metamodelUri, extension); uriConfigElementMap.put(metamodelUri, elements[j]); } else { Util.log(IStatus.ERROR, Util.getString(PREFIX + "invalidModelId", //$NON-NLS-1$ new Object[] {extension.getClass().getName()})); } } else { Util.log(IStatus.ERROR, Util.getString(PREFIX + "invalidMapperClass", //$NON-NLS-1$ new Object[] {extension.getClass().getName()})); } } catch (Exception theException) { Util.log(IStatus.ERROR, theException, Util.getString(PREFIX + "loadingMapperProblem", //$NON-NLS-1$ new Object[] {elements[j].getAttribute(CLASSNAME)})); } } } } } /** * Creates the <code>ITreeToRelationalMapper</code> for the specified metamodel URI. * * @param theMetamodelUri the metamodel URI whose mapper is being requested * @return the mapper or <code>null</code> if none found * @throws IllegalArgumentException if the metamodel URI is <code>null</code> or empty */ public static ITreeToRelationalMapper createModelMapper( String theMetamodelUri ) { CoreArgCheck.isNotNull(theMetamodelUri); CoreArgCheck.isNotEmpty(theMetamodelUri); ITreeToRelationalMapper result = null; IConfigurationElement configElement = (IConfigurationElement)uriConfigElementMap.get(theMetamodelUri); if (configElement != null) { try { result = (ITreeToRelationalMapper)configElement.createExecutableExtension(CLASSNAME); } catch (CoreException theException) { Util.log(IStatus.ERROR, Util.getString(PREFIX + "createMapperProblem", //$NON-NLS-1$ new Object[] {theMetamodelUri, configElement.getAttribute(CLASSNAME)})); } } return result; } /** * Creates the appropriate <code>ITreeToRelationalMapper</code> for the specified tree node. * * @param theTreeNode the tree node whose mapper is being requested * @return the mapper or <code>null</code> if none exists * @throws IllegalArgumentException if the tree node is <code>null</code> */ public static ITreeToRelationalMapper createModelMapper( EObject theTreeNode ) { CoreArgCheck.isNotNull(theTreeNode); ITreeToRelationalMapper result = null; String uri = getMetamodelUri(theTreeNode); if (uri != null) { result = createModelMapper(uri); } if (result != null) { result.setTreeRoot(theTreeNode); } return result; } /** * Obtains the metamodel URI for the specified tree node. If the tree node is contained within an EMF resource that is not a * Teiid Designer model resource, for example an XSD resource, then null will be returned. * * @param theTreeNode the tree node whose metamodel URI is being requested * @return the metamodel URI; may return null for unsupported metamodels * @throws IllegalArgumentException if the tree node is <code>null</code> */ private static String getMetamodelUri( EObject theTreeNode ) { CoreArgCheck.isNotNull(theTreeNode); // Get the container to use when resolving the EObject if it is a proxy ... Container container = ModelerCore.getContainer(theTreeNode); if (container == null) { try { // The container is null if "theTreeNode" is a proxy container = ModelerCore.getModelContainer(); } catch (CoreException err) { ModelerCore.Util.log(err); } } // First try finding the primary metamodel URI directly from the EMF resource ... Resource eResource = ModelerCore.getModelEditor().findResource(container, theTreeNode); if (eResource instanceof EmfResource) { final ModelAnnotation annot = ((EmfResource)eResource).getModelAnnotation(); if (annot != null && annot.getPrimaryMetamodelUri() != null) { return annot.getPrimaryMetamodelUri(); } } return null; } /** * Indicates if the specified tree node is a root in one of the loaded <code>ITreeToRelationalMapper</code>s. * * @param theTreeNode the tree node being checked * @return <code>true</code> if a tree root; <code>false</code> otherwise. * @throws IllegalArgumentException if the tree node is <code>null</code> */ public static boolean isTreeRoot( EObject theTreeNode ) { CoreArgCheck.isNotNull(theTreeNode); boolean result = false; String uri = getMetamodelUri(theTreeNode); if (uri != null) { ITreeToRelationalMapper mapper = (ITreeToRelationalMapper)uriMapperMap.get(uri); if (mapper == null) { // put null value in map for URI for efficiency if (!uriMapperMap.containsKey(uri)) { uriMapperMap.put(uri, null); } } else { result = mapper.isTreeRoot(theTreeNode); } } return result; } /** * Indicates if the specified tree node is a root in one of the loaded <code>ITreeToRelationalMapper</code>s. * * @param theTreeNode the tree node being checked * @return <code>true</code> if a tree root; <code>false</code> otherwise. * @throws IllegalArgumentException if the tree node is <code>null</code> */ public static boolean isXmlTreeNode( EObject theTreeNode ) { CoreArgCheck.isNotNull(theTreeNode); boolean result = false; // Get the metamodel URI associated with this EObject. The URI that is // returned may not be the primary metamodel URI of the resource if this // EObject is from one of our participatory metamodels (e.g. Diagrams, Transformation, ...) String uri = theTreeNode.eClass().getEPackage().getNsURI(); ITreeToRelationalMapper mapper = (ITreeToRelationalMapper)uriMapperMap.get(uri); if (mapper != null) { result = mapper.isTreeNode(theTreeNode); } return result; } /** * gets the parent tree root for a specifed tree node is a tree (document). * * @param someTreeNode the tree node starting point * @return treeRoot EObject */ public static EObject getTreeRoot( EObject someTreeNode ) { // Need to walk it's parents until you get isTreeRoot(node) == TRUE EObject treeRoot = null; if (isTreeRoot(someTreeNode)) { treeRoot = someTreeNode; } else if (someTreeNode.eContainer() != null) { EObject parent = someTreeNode.eContainer(); // in case we accidently get to the model resource... boolean failure = false; while (treeRoot == null && !failure) { if (isTreeRoot(parent)) { treeRoot = parent; } else { if (parent.eContainer() != null) parent = parent.eContainer(); else failure = true; } } } return treeRoot; } /** * Provides access to xml document tree node xsd component via a loaded <code>ITreeToRelationalMapper</code>s. * * @param theTreeNode the tree node being checked * @return <code>EObject</code> xsd component * @throws IllegalArgumentException if the tree node is <code>null</code> */ public static EObject getXsdComponent( EObject theTreeNode ) { CoreArgCheck.isNotNull(theTreeNode); EObject result = null; // Get the metamodel URI associated with this EObject. The URI that is // returned may not be the primary metamodel URI of the resource if this // EObject is from one of our participatory metamodels (e.g. Diagrams, Transformation, ...) String uri = theTreeNode.eClass().getEPackage().getNsURI(); ITreeToRelationalMapper mapper = (ITreeToRelationalMapper)uriMapperMap.get(uri); if (mapper != null) { result = mapper.getXsdComponent(theTreeNode); } return result; } }