/*
* 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.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.mapping.MappingRoot;
import org.teiid.core.designer.ModelerCoreException;
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.util.ModelResourceContainerFactory;
import org.teiid.designer.mapping.PluginConstants;
import org.teiid.designer.metamodels.transformation.MappingClass;
import org.teiid.designer.metamodels.transformation.MappingClassColumn;
import org.teiid.designer.metamodels.transformation.StagingTable;
import org.teiid.designer.metamodels.transformation.TransformationMappingRoot;
import org.teiid.designer.metamodels.transformation.TreeMappingRoot;
/**
* The <code>TreeMappingAdapter</code> class
*
* @since 8.0
*/
public class TreeMappingAdapter implements PluginConstants {
//private PerformanceTracker pTracker = new PerformanceTracker(getClass().getName());
///////////////////////////////////////////////////////////////////////////////////////////////
// CONSTANTS
///////////////////////////////////////////////////////////////////////////////////////////////
/** Properties file key prefix. Used for logging and localization. */
private static final String PREFIX = I18nUtil.getPropertyPrefix(TreeMappingAdapter.class);
///////////////////////////////////////////////////////////////////////////////////////////////
// FIELDS
///////////////////////////////////////////////////////////////////////////////////////////////
/** The tree root. */
private EObject root;
/** Structure content object to keep efficiently keep track of mapping classes, staging tables and their referenced locations
* in XML Document tree
* */
private TreeMappingClassLocator mappingLocator;
private boolean generatingMappingClasses = false;
//private boolean doTrack = true;
///////////////////////////////////////////////////////////////////////////////////////////////
// CONSTRUCTORS
///////////////////////////////////////////////////////////////////////////////////////////////
/**
* Constructs a <code>TreeMappingAdapter</code> for the specified tree root.
* @param theTreeRoot the tree root
*/
public TreeMappingAdapter(EObject theTreeRoot) {
//startTracking("TreeMappingAdapter()"); //$NON-NLS-1$
CoreArgCheck.isNotNull(theTreeRoot);
mappingLocator = new TreeMappingClassLocator(theTreeRoot);
root = theTreeRoot;
mappingLocator.loadTreeNodesToMappingClassScopeMap();
//stopTracking("TreeMappingAdapter()"); //$NON-NLS-1$
}
///////////////////////////////////////////////////////////////////////////////////////////////
// METHODS
///////////////////////////////////////////////////////////////////////////////////////////////
// public void resetTracker() {
// pTracker.reset();
// mappingLocator.resetTracker();
// }
//
//
// public void print() {
// pTracker.print();
// mappingLocator.print();
// //System.out.println(mappingLocator.toString());
// }
//
// private void startTracking(String method) {
// if( doTrack ) {
// pTracker.start(method);
// }
// }
//
// private void stopTracking(String method) {
// if( doTrack ) {
// pTracker.stop(method);
// }
// }
public boolean isGeneratingMappingClasses() {
return generatingMappingClasses;
}
public void setGeneratingMappingClasses(boolean isGenerating) {
this.generatingMappingClasses = isGenerating;
mappingLocator.setGeneratingMappingClasses(isGenerating);
}
public void addMappingClassAtLocation(EObject treeMappingRoot, MappingClass theMappingClass, EObject location) {
mappingLocator.addMappingClassAtLocation(treeMappingRoot, theMappingClass, location);
}
public List getAllMappingClassLocations() {
return new ArrayList(mappingLocator.getAllMappingClassLocations());
}
public void addStagingTableAtLocation(EObject treeMappingRoot, StagingTable theStagingTable, EObject location) {
mappingLocator.addMappingClassAtLocation(treeMappingRoot, theStagingTable, location);
}
public boolean containsMappingClassWithName(String someName) {
return mappingLocator.containsMappingClassWithName(someName);
}
/**
* Maps the specified <code>MappingClass</code> to the specified tree node (<code>EObject</code>).
* @param theMappingClass the <code>Mapping</code> input
* @param theTreeNode the <code>Mapping</code> output
* @throws IllegalArgumentException if either input parameter is <code>null</code>
*/
public void addMappingClassLocation( MappingClass theMappingClass, EObject theTreeNode ) {
//startTracking("addMappingClassLocation()"); //$NON-NLS-1$
CoreArgCheck.isNotNull(theMappingClass);
CoreArgCheck.isNotNull(theTreeNode);
if( ! mappingLocator.containsLocation(theMappingClass, theTreeNode) ) {
try {
TreeMappingRoot treeMappingRoot = (TreeMappingRoot)mappingLocator.getMappingRoot(theMappingClass);
mappingLocator.addOutputLocation(theMappingClass, theTreeNode);
// if( !isGeneratingMappingClasses() ) {
addMappingClassAtLocation(treeMappingRoot, theMappingClass, theTreeNode);
// }
} catch (Exception e) {
PluginConstants.Util.log(IStatus.ERROR, e, e.getMessage());
}
}
//stopTracking("addMappingClassLocation()"); //$NON-NLS-1$
}
/**
* Maps the specified <code>MappingClassColumn</code> to the specified tree node (<code>EObject</code>).
* @param theMappingColumn the <code>Mapping</code> input
* @param theTreeNode the <code>Mapping</code> output
* @throws IllegalArgumentException if either input parameter is <code>null</code>
*/
public void addMappingClassColumnLocation(MappingClassColumn theMappingColumn, EObject theTreeNode) {
//startTracking("addMappingClassColumnLocation()"); //$NON-NLS-1$
CoreArgCheck.isNotNull(theMappingColumn);
CoreArgCheck.isNotNull(theTreeNode);
mappingLocator.addMappingClassColumnLocation(theMappingColumn, theTreeNode);
//stopTracking("addMappingClassColumnLocation()"); //$NON-NLS-1$
}
/**
* Creates a {@link MappingRoot} having the specified <code>MappingClass</code> as it's input.
* @param theMappingClass the <code>MappingClass</code> used to create the mapping root
* @return the index in the <code>mappingRoots</code> list of the new root
* @throws IllegalArgumentException if input parameter is <code>null</code>
*/
public EObject createTreeMappingRoot(MappingClass theMappingClass) {
//startTracking("createTreeMappingRoot(GENERATING)"); //$NON-NLS-1$
CoreArgCheck.isNotNull(theMappingClass);
if( mappingLocator.hasTreeRoot(theMappingClass) ) {
return mappingLocator.getMappingRoot(theMappingClass);
}
TreeMappingRoot newRoot = null;
try {
// Defect 18433 - BML 8/31/05 - Changed call to create tree mapping root using a new
// utility method that correctly adds it to the model (via addValue()) and also performs
// additional work (i.e.adding nested Sql Helpers.
newRoot = ModelResourceContainerFactory.createNewTreeMappingRoot(this.root, this.root.eResource());
// Now add the mapping class to the Inputs list of the tree mapping root
ModelerCore.getModelEditor().addValue(newRoot, theMappingClass, newRoot.getInputs());
} catch (Exception theException) {
Util.log(IStatus.ERROR,
theException,
Util.getString(PREFIX + "createMappingRootProblem", //$NON-NLS-1$
new Object[] {root, theMappingClass}));
}
//stopTracking("createTreeMappingRoot(GENERATING)"); //$NON-NLS-1$
return newRoot;
}
/**
* Obtains all {@link MappingClass}es for this adapter's tree root.
* @return the <code>MappingClass</code>es or an empty list
*/
public List getAllMappingClasses() {
//startTracking("getAllMappingClasses()"); //$NON-NLS-1$
List returnList = Collections.unmodifiableList(mappingLocator.getMappingClasses());
//stopTracking("getAllMappingClasses()"); //$NON-NLS-1$
return returnList;
}
/**
* Obtains all {@link StagingTable} for this adapter's tree root.
* @return the <code>StagingTable</code>s or an empty list
*/
public List getAllStagingTables() {
return Collections.unmodifiableList(mappingLocator.getStagingTables());
}
/**
* Obtains the <code>FragmentMappingAdapter</code> for this adapter's tree root.
* @return the <code>FragmentMappingAdapter</code> (never <code>null</code>)
*/
public FragmentMappingAdapter getFragmentMappingAdapter() {
return mappingLocator.getFragmentAdapter();
}
/**
* Obtains the tree node where the specified <code>StagingTable</code> is mapped.
* @param theStagingTable the <code>StagingTable</code> whose mapped tree node is being requested
* @return the mapped tree node
* @throws IllegalArgumentException if input parameter is <code>null</code>
*/
public EObject getStagingTableOutputLocation(StagingTable theStagingTable) {
return mappingLocator.getStagingTableLocation(theStagingTable);
}
/**
* Obtains all tree nodes that are mapped to the specified <code>MappingClass</code>.
* @param theMappingClass the <code>MappingClass</code> whose mapped tree nodes are being requested
* @return an unmodifiable list of mapped tree nodes or an empty list
* @throws IllegalArgumentException if input parameter is <code>null</code>
*/
public List getMappingClassOutputLocations(MappingClass theMappingClass) {
//startTracking("getMappingClassOutputLocations()"); //$NON-NLS-1$
List resultsList = Collections.unmodifiableList(mappingLocator.getMappingClassLocations(theMappingClass));
//stopTracking("getMappingClassOutputLocations()"); //$NON-NLS-1$
return resultsList;
}
/**
* Obtains the tree nodes that are mapped to the specified <code>MappingClassColumn</code>.
* @param theMappingColumn the <code>MappingClassColumn</code> whose mapped tree nodes are being requested
* @return an unmodifiable list of mapped tree nodes or an empty list
* @throws IllegalArgumentException if input parameter is <code>null</code>
*/
public List getMappingClassColumnOutputLocations(MappingClassColumn theMappingColumn) {
return mappingLocator.getMappingClassColumnOutputLocations(theMappingColumn);
}
/**
* Return the StagingTable located at the specified node, if one exists at this node.
* @param theTreeNode
* @return
*/
public StagingTable getStagingTable(EObject theTreeNode) {
CoreArgCheck.isNotNull(theTreeNode);
return (StagingTable)mappingLocator.getStagingTable(theTreeNode);
}
/**
* Return the MappingClass located at the specified node, if one exists at this node.
* @param theTreeNode
* @return
*/
public EObject getMappingClassLocation( MappingClass theMappingClass ) {
//startTracking("getMappingClassLocation()"); //$NON-NLS-1$
CoreArgCheck.isNotNull( theMappingClass );
List locations = mappingLocator.getMappingClassLocations( theMappingClass );
EObject location = null;
if( !locations.isEmpty() ) {
location = (EObject)locations.get(0);
}
//stopTracking("getMappingClassLocation()"); //$NON-NLS-1$
return location;
}
/**
* Return the MappingClass located at the specified node, if one exists at this node.
* @param theTreeNode
* @return
*/
public MappingClass getMappingClass(EObject theTreeNode) {
CoreArgCheck.isNotNull(theTreeNode);
return (MappingClass) mappingLocator.getMappingClass(theTreeNode);
}
public MappingClassColumn getMappingClassColumn(EObject theTreeNode, MappingClass theMappingClass) {
CoreArgCheck.isNotNull(theTreeNode);
MappingClassColumn result = mappingLocator.getMappingClassColumn(theTreeNode, theMappingClass);
return result;
}
public MappingClass getMappingClassForTreeNode(EObject theTreeNode) {
return mappingLocator.getMappingClassForTreeNode(theTreeNode);
}
/**
* Obtain an ordered list of all locations visible in the TreeViewer that are in the extent
* of the specified MappingClass.
* This method is based on getCoarseMappingExtentNodes(MappingClass theMappingClass) from
* MappingAdapterFilter.
* @param theMappingClass
* @return
*/
public List getTreeNodesInAMappingClassScope(MappingClass theMappingClass) {
//startTracking("getTreeNodesInAMappingClassScope()"); //$NON-NLS-1$
List extentNodes = mappingLocator.getTreeNodesInAMappingClassScope(theMappingClass);
//stopTracking("getTreeNodesInAMappingClassScope()"); //$NON-NLS-1$
return extentNodes;
}
/**
* return a list of all location mapped to the attributes of the specified MappingClass
* @param theMappingClass
* @return
*/
public List getColumnLocations(MappingClass theMappingClass) {
return mappingLocator.getColumnLocations(theMappingClass);
}
/**
* Obtains the <code>MappingClassColumn</code> where the specified tree node is mapped.
* @param theTreeNode the tree node whose <code>MappingClassColumn</code> is being requested
* @return the <code>MappingClassColumn</code> or <code>null</code> if not mapped
*/
public MappingClassColumn getMappingClassColumn( EObject theTreeNode ) {
/*
* jh Lyra enh:
*
* This is a linear search, and the MCs are not necessarily in any
* optimal order. Let's replace this with a HashMap.
*
* jhTODO
* Major question: This map is created in the constructor of this class;
* Should it be recreated any other times prior to
* recreating this class (TreeMappingAdapter)?
* Yes: on NewMappingLinkAction and DeleteMappingLinksAction
* [fixed 2/1/2006]
*/
CoreArgCheck.isNotNull(theTreeNode);
MappingClassColumn result = mappingLocator.getMappingClassColumn(theTreeNode);
//
// result = (MappingClassColumn)getTreeNodesToMappingClassColumnsMap( false ).get( theTreeNode );
//
return result;
}
/**
* Indicates if the specified tree node has been mapped.
* @param theTreeNode the tree node whose mapped status is being requested
* @return <code>true</code> if mapped; <code>false</code> otherwise.
* @throws IllegalArgumentException if input parameter is <code>null</code>
*/
public boolean isMapped(EObject theTreeNode) {
CoreArgCheck.isNotNull(theTreeNode);
return getMappingClassColumn(theTreeNode) != null;
}
/**
* Indicates if the specified tree node has been mapped.
* @param theTreeNode the tree node whose mapped status is being requested
* @return <code>true</code> if mapped; <code>false</code> otherwise.
* @throws IllegalArgumentException if input parameter is <code>null</code>
*/
public StagingTable getStagingTableForRootTreeNode( EObject theTreeNode ) {
return (StagingTable) mappingLocator.getStagingTable(theTreeNode);
}
/**
* Removes the specified {@link org.eclipse.emf.mapping.Mapping}.
* @param theMappingClass the <code>Mapping</code> input
* @param theTreeNode the <code>Mapping</code> output
* @throws IllegalArgumentException if either input parameter is <code>null</code>
*/
public void removeMappingClassLocation(MappingClass theMappingClass,
EObject theTreeNode) {
CoreArgCheck.isNotNull(theMappingClass);
CoreArgCheck.isNotNull(theTreeNode);
try {
mappingLocator.removeOutputLocation(theMappingClass, theTreeNode);
} catch (Exception e) {
Util.log(IStatus.ERROR, e, Util.getString(PREFIX + "removeLocationTreeNodeNotFound", //$NON-NLS-1$
new Object[] {theTreeNode,
"MappingClass", //$NON-NLS-1$
theMappingClass}));
}
}
/**
* Deletes all mappings associated with the specified MappingClass, but does not delete
* the MappingClass itself.
* @param theMappingClass
* @throws ModelerCoreException
*/
public void deleteMappingClass(MappingClass theMappingClass) throws ModelerCoreException {
CoreArgCheck.isNotNull(theMappingClass);
mappingLocator.deleteMappingClass(theMappingClass);
}
/**
* Removes the specified {@link org.eclipse.emf.mapping.Mapping}.
* @param theMappingColumn the <code>Mapping</code> input
* @param theTreeNode the <code>Mapping</code> output
* @throws IllegalArgumentException if either input parameter is <code>null</code>
*/
public void removeMappingClassColumnLocation(MappingClassColumn theMappingColumn,
EObject theTreeNode) {
CoreArgCheck.isNotNull(theMappingColumn);
CoreArgCheck.isNotNull(theTreeNode);
mappingLocator.removeMappingClassColumnLocation(theMappingColumn, theTreeNode);
}
public List getParentMappingClasses(MappingClass theMappingClass, EObject docRoot, boolean includeStagingTables) {
return getParentMappingClasses(theMappingClass, new DefaultMappableTree(docRoot), includeStagingTables);
}
/**
* Obtain an ordered list of all MappingClasses located above the specified instance.
* Note: this method may also be called for StagingTables, which extend MappingClass.
* @param theMappingClass the MappingClass or StagingTable
* @return
*/
public List getParentMappingClasses(MappingClass theMappingClass, IMappableTree theMappableTree, boolean includeStagingTables) {
List result = new ArrayList();
List locations = null;
if ( theMappingClass instanceof StagingTable ) {
locations = new ArrayList();
locations.add(getStagingTableOutputLocation((StagingTable) theMappingClass));
} else {
locations = new ArrayList();
locations.addAll(getMappingClassOutputLocations(theMappingClass));
}
List mappingClasses = getAllMappingClasses();
for ( Iterator iter = mappingClasses.iterator() ; iter.hasNext() ; ) {
MappingClass mc = (MappingClass) iter.next();
MAPPING_CLASS_LOOP:
if ( mc != null && ! mc.equals(theMappingClass) ) {
for ( Iterator testLocIter = getMappingClassOutputLocations(mc).iterator() ; testLocIter.hasNext() && locations.size() != 0; ) {
EObject possibleLoc = (EObject) testLocIter.next();
for ( int i=0 ; i<locations.size() ; ++i ) {
// mc is a parent if one of it's locations is an ancestor of theMappingClass's location
if ( theMappableTree.isAncestorOf(possibleLoc, (EObject) locations.get(i)) ) {
result.add(mc);
break MAPPING_CLASS_LOOP;
}
}
}
}
}
return result;
}
/**
* Obtain the document node eObject for this mapping
* @return
*/
public EObject getDocument() {
List mappingRoots = mappingLocator.getMappingRoots();
if( mappingRoots != null && !mappingRoots.isEmpty() ) {
EObject firstRoot = (EObject)mappingRoots.get(0);
if( firstRoot != null && firstRoot instanceof TransformationMappingRoot ) {
return ((TransformationMappingRoot)firstRoot).getTarget();
}
}
return null;
}
}