/******************************************************************************* * Copyright (c) 2010 SAP AG. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * Emil Simeonov - initial API and implementation. * Dimitar Donchev - initial API and implementation. * Dimitar Tenev - initial API and implementation. * Nevena Manova - initial API and implementation. * Georgi Konstantinov - initial API and implementation. *******************************************************************************/ package org.eclipse.wst.sse.sieditor.ui.v2.factory; import java.lang.ref.WeakReference; import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Stack; import org.eclipse.emf.ecore.EObject; import org.eclipse.wst.wsdl.WSDLElement; import org.eclipse.xsd.XSDConcreteComponent; import org.eclipse.xsd.XSDSchema; import org.eclipse.wst.sse.sieditor.model.api.IModelObject; import org.eclipse.wst.sse.sieditor.model.utils.EmfWsdlUtils; import org.eclipse.wst.sse.sieditor.model.utils.EmfXsdUtils; import org.eclipse.wst.sse.sieditor.model.wsdl.impl.Description; import org.eclipse.wst.sse.sieditor.model.xsd.api.ISchema; import org.eclipse.wst.sse.sieditor.ui.v2.nodes.ITreeNode; import org.eclipse.wst.sse.sieditor.ui.v2.wsdltree.nodes.ServiceInterfaceNode; /** * * This class is used to store the nodes created, along with their model * elements. So that we can get a node from a given model element. It is * populated the first time a node is created, and removed when a node is * deleted. */ public class TreeNodeMapper { private Map<IModelObject, List<WeakReference<ITreeNode>>> nodeMap = new HashMap<IModelObject, List<WeakReference<ITreeNode>>>(); /* * Stores the model object and a map with category and tree node * corresponding to that Used in cases of datatype nodes, which have * built-in, inline and project types categories Also used for Input, Output * and Fault categories in the left tree */ private Map<Object, Map<String, ITreeNode>> categoryNodeMap = new HashMap<Object, Map<String, ITreeNode>>(); /** * Returns the first tree node which is not CATEGORY_REFERENCE. If there is * no such node, then return the first CATEGORY_REFERENCE node for the given * model element. Because a model object can has more than one tree node * this method is deprecated. * * @deprecated use {@link #getTreeNode(IModelObject, Collection, ITreeNode)} * @param modelObject * @return the first tree node mapped to the model object or null if no such * is found */ public ITreeNode getTreeNode(final IModelObject modelObject) { ExcludeCategoryMatcher excludeCategories = new ExcludeCategoryMatcher(ITreeNode.CATEGORY_REFERENCE); List<ITreeNode> foundTreeNodes = getTreeNode(modelObject, excludeCategories); if (!foundTreeNodes.isEmpty()) { return foundTreeNodes.get(0); } List<WeakReference<ITreeNode>> treeNodes = nodeMap.get(modelObject); ITreeNode firstTreeNode = null; if (treeNodes != null && !treeNodes.isEmpty()) { Iterator<WeakReference<ITreeNode>> treeNodesIterator = treeNodes.iterator(); while (firstTreeNode == null && treeNodesIterator.hasNext()) { WeakReference<ITreeNode> weakTreeNode = treeNodesIterator.next(); firstTreeNode = weakTreeNode.get(); if (firstTreeNode == null) { treeNodesIterator.remove(); } } } return firstTreeNode; } /** * Get tree nodes that corresponds to the modelObject, its parent tree node * and all categories from categories list. * * @param modelObject * for which tree nodes map will be searched for * @param categories * categories which the returned tree nodes must have * @param parentNode * in case that is null, children with null parent will be * searched for categories * @return never returns null */ public List<ITreeNode> getTreeNode(final IModelObject modelObject, int categories, ITreeNode parentNode) { ParentCategoryMatcher matcher = new ParentCategoryMatcher(categories, parentNode); return getTreeNode(modelObject, matcher); } /** * Gets all the tree nodes that match at least one of the given categories * * @param modelObject * @param categories * @return */ public List<ITreeNode> getTreeNode(final IModelObject modelObject, int categories) { CategoryMatcher matcher = new CategoryMatcher(categories); return getTreeNode(modelObject, matcher); } /** * Get tree nodes that corresponds to the modelObject, its parent tree node * and all categories of the parent node. * * @param parentNode * must not be null, because its categories will be used * @return never returns null * @see #getTreeNode(IModelObject, int, ITreeNode) */ public List<ITreeNode> getTreeNode(final IModelObject modelObject, ITreeNode parentNode) { return this.getTreeNode(modelObject, parentNode.getCategories(), parentNode); } private List<ITreeNode> getTreeNode(final IModelObject modelObject, IMatch matcher) { List<ITreeNode> matchedTreeNodes = new ArrayList<ITreeNode>(); List<WeakReference<ITreeNode>> treeNodes = nodeMap.get(modelObject); if (treeNodes != null && !treeNodes.isEmpty()) { Iterator<WeakReference<ITreeNode>> treeNodesIterator = treeNodes.iterator(); while (treeNodesIterator.hasNext()) { WeakReference<ITreeNode> weakTreeNode = treeNodesIterator.next(); ITreeNode treeNode = weakTreeNode.get(); if (treeNode == null) { treeNodesIterator.remove(); } else if (matcher.isTreeNodeMatching(treeNode)) { matchedTreeNodes.add(treeNode); } } } return matchedTreeNodes; } private interface IMatch { boolean isTreeNodeMatching(ITreeNode node); } private class CategoryMatcher implements IMatch { private int categories; CategoryMatcher(int categories) { this.categories = categories; } public boolean isTreeNodeMatching(ITreeNode node) { return (node.getCategories() & categories) != 0; } } private class ExcludeCategoryMatcher implements IMatch { private int categoriesToExclude; ExcludeCategoryMatcher(int categoriesToExclude) { this.categoriesToExclude = categoriesToExclude; } public boolean isTreeNodeMatching(ITreeNode node) { return (node.getCategories() & categoriesToExclude) == 0; } } private class ParentCategoryMatcher implements IMatch { private ITreeNode parentNode; private int categories; ParentCategoryMatcher(int categories, ITreeNode parentNode) { this.categories = categories; this.parentNode = parentNode; } @Override public boolean isTreeNodeMatching(ITreeNode node) { return (node.getCategories() & categories) == categories && (parentNode == null ? node.getParent() == null : parentNode.equals(node.getParent())); } } /** * Returns the Category node for a given model object * * @param category * @param modelObject * @return */ public ITreeNode getCategoryNode(final String category, final Object modelObject) { if (categoryNodeMap.containsKey(modelObject)) { Map<String, ITreeNode> categoryMap = categoryNodeMap.get(modelObject); if (categoryMap != null) { if (categoryMap.containsKey(category)) return categoryMap.get(category); } } return null; } /** * Do always check for an existing tree node with specific categories/parent * node, before adding a new one. * * @see #getTreeNode(IModelObject, int, ITreeNode) */ public void addToNodeMap(final IModelObject modelObject, final ITreeNode treeNode) { List<WeakReference<ITreeNode>> treeNodes = nodeMap.get(modelObject); if (treeNodes == null) { treeNodes = new ArrayList<WeakReference<ITreeNode>>(); nodeMap.put(modelObject, treeNodes); } treeNodes.add(new WeakReference<ITreeNode>(treeNode)); } public void addToCategoryNodeMap(final String category, final Object modelObject, final ITreeNode node) { if (categoryNodeMap.containsKey(modelObject)) { Map<String, ITreeNode> categoryMap = categoryNodeMap.get(modelObject); if (categoryMap != null) categoryMap.put(category, node); } else { Map<String, ITreeNode> categoryMap = new HashMap<String, ITreeNode>(); categoryMap.put(category, node); categoryNodeMap.put(modelObject, categoryMap); } } /** * This method removes all tree nodes associated with one model object. * * @param modelObject * for which to delete all associated tree nodes * @see #removeNodeFromMap(ITreeNode) */ public void removeNodeFromMap(final IModelObject modelObject) { nodeMap.remove(modelObject); } /** * This method removes a single tree node instance from tree nodes map. * * @param treeNode * to remove */ public void removeNodeFromMap(final ITreeNode treeNode) { IModelObject modelObject = treeNode.getModelObject(); List<WeakReference<ITreeNode>> treeNodes = nodeMap.get(modelObject); if (treeNodes == null) { return; } Iterator<WeakReference<ITreeNode>> treeNodesIterator = treeNodes.iterator(); while (treeNodesIterator.hasNext()) { ITreeNode treeNodeFromMap = treeNodesIterator.next().get(); if (treeNodeFromMap == null || treeNode.equals(treeNodeFromMap)) { treeNodesIterator.remove(); } } } // Removes from category node map public void removeCategoryNodeFromMap(final String category, final Object modelObject) { if (category != null && modelObject != null) { if (categoryNodeMap.containsKey(modelObject)) { Map<String, ITreeNode> categoryMap = categoryNodeMap.get(modelObject); if (categoryMap != null) { if (categoryMap.containsKey(category)) categoryMap.remove(category); if (categoryMap.isEmpty()) categoryNodeMap.remove(modelObject); } } } } public void clearAllNodesFromMap() { categoryNodeMap.clear(); nodeMap.clear(); } /** * Return the corresponding ITreeNode for a given XSDConcretComponent * object, or null if the ITreeNode missing * * @param modelObject * is IWsdlModelRoot( in case of SIE) or IXsdModelRoot(in case if * DTE), MUST be not null * @param searchedObject * is XsdElement * @return */ public ITreeNode getITreeNodeForXsdElement(final IModelObject modelObject, XSDConcreteComponent searchedObject) { if (!EmfXsdUtils.hasCorrespondingITreeNode(searchedObject)) { return null; } ISchema schema = (ISchema) modelObject; ITreeNode schemaNode = getTreeNode(schema); if (schemaNode == null) { return null; } XSDSchema schemaComponent = schema.getComponent(); if (schemaComponent.hashCode() == searchedObject.hashCode()) { return schemaNode; } Stack<EObject> emfPathToTheObject = new Stack<EObject>(); emfPathToTheObject.push(searchedObject); EObject pathCreator = searchedObject.eContainer(); while (pathCreator != schemaComponent && pathCreator != null) { if (EmfXsdUtils.hasCorrespondingITreeNode(pathCreator)) { emfPathToTheObject.push(pathCreator); } pathCreator = pathCreator.eContainer(); } ITreeNode result = getXsdITreeNode(schemaNode, emfPathToTheObject); if (result != null) { return result; } return null; } /** * Recursive searching process in EMF path and as a result the method return * ITreeNode from DTPage which correspond to the bottom of the path, or null * otherwise * * @param node * is current processing ITreeNode * @param emfPathToTheObject * is a path to the EMF object * @return ITreeNode which is part of the treeViewer in DataTypesPage */ private ITreeNode getXsdITreeNode(ITreeNode node, Stack<EObject> emfPathToTheObject) { if (emfPathToTheObject.empty()) { return node; } EObject currentEObject = emfPathToTheObject.pop(); ITreeNode treeNode = null; for (Object currentNode : node.getChildren()) { treeNode = (ITreeNode) currentNode; ITreeNode nodeFromEmfPath = checkXsdElement(treeNode, (XSDConcreteComponent) currentEObject); if (nodeFromEmfPath != null) { return getXsdITreeNode(nodeFromEmfPath, emfPathToTheObject); } } return null; } private ITreeNode checkXsdElement(ITreeNode currentTreeNode, EObject emfComponent) { XSDConcreteComponent currentXsdComponent = (XSDConcreteComponent) currentTreeNode.getModelObject().getComponent(); if (currentXsdComponent.hashCode() == emfComponent.hashCode() || currentXsdComponent.hashCode() == ((XSDConcreteComponent) emfComponent).getContainer().hashCode()) { return currentTreeNode; } return null; } /** * Return the corresponding ITreeNode for a given EMF object, or null if the * ITreeNode missing * * @param modelObject * is IWsdlModelRoot, must be not null * @param searchedObject * is WSDLElement * @param portTypes * i s List of all ServiceInterface nodes * @return */ public ITreeNode getITreeNodeForWsdlElement(final IModelObject modelObject, final EObject searchedObject, List<ServiceInterfaceNode> portTypes) { if (!EmfWsdlUtils.hasCorrespondingITreeNode(searchedObject)) { return null; } ITreeNode result = null; for (ITreeNode currentTreeNode : portTypes) { EObject emfComponentForCurrentTreeNode = currentTreeNode.getModelObject().getComponent(); if (emfComponentForCurrentTreeNode.hashCode() == searchedObject.hashCode()) { return currentTreeNode; } result = getWsdlITreeNode(currentTreeNode, searchedObject); if (result != null) { return result; } } return result; } /** * Recursive search process which return corresponding ITreeNode for a given * WSDLElement, or null otherwise * * @param node * is and ITreeNode from the treeViewer in Service Interface Page * @param searchedComponent * is and WSDL EMF Object * @return corresponding ITreeNode to the "searchedComponent" */ private ITreeNode getWsdlITreeNode(final ITreeNode node, final EObject searchedComponent) { if (node == null || !node.hasChildren()) { return null; } ITreeNode currentNode; for (Object currentChild : node.getChildren()) { currentNode = (ITreeNode) currentChild; WSDLElement currentWsdlComponent = (WSDLElement) currentNode.getModelObject().getComponent(); if (currentWsdlComponent.hashCode() == searchedComponent.hashCode()) { return currentNode; } ITreeNode treeNode = getWsdlITreeNode(currentNode, searchedComponent); if (treeNode != null) { return treeNode; } } return null; } }