/******************************************************************************* * Copyright (c) 2010 SAP AG and others. * 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: * SAP AG - initial API and implementation ******************************************************************************/ package com.sap.furcas.prettyprinter.incremental; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.HashMap; import java.util.Map; import org.eclipse.emf.ecore.EObject; import com.sap.furcas.metamodel.FURCAS.TCS.ConcreteSyntax; import com.sap.furcas.metamodel.FURCAS.TCS.Template; import com.sap.furcas.metamodel.FURCAS.textblocks.DocumentNode; import com.sap.furcas.metamodel.FURCAS.textblocks.TextBlock; /** * <p> * A simple class used to index TextBlocks so that those can be easily searched * by the {@link TextBlockBasedPrintPolicy}, which needs to know * if we have already have old TextBlocks for existing model elements. * </p> * * The method {@link #index(TextBlock)} should be called for each potentially * reusable TextBlocks tree. * * @author Stephan Erb * */ public class TextBlockIndex { private static class ModelElementKey { public final EObject correspondingModelElement; private final ConcreteSyntax syntax; private final Template template; public ModelElementKey(ConcreteSyntax syntax, Template template, EObject correspondingModelElement) { this.template = template; this.correspondingModelElement = correspondingModelElement; this.syntax = syntax; } @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + ((correspondingModelElement == null) ? 0 : correspondingModelElement.hashCode()); result = prime * result + ((syntax == null) ? 0 : syntax.hashCode()); result = prime * result + ((template == null) ? 0 : template.hashCode()); return result; } @Override public boolean equals(Object obj) { if (!(obj instanceof ModelElementKey)) { return false; } ModelElementKey other = (ModelElementKey) obj; return other.correspondingModelElement.equals(this.correspondingModelElement) && other.syntax.equals(this.syntax) && (other.template == null && this.template == null || other.template != null && other.template.equals(this.template)); } } private final Map<ModelElementKey, Collection<TextBlock>> blockIndexPerModelElement = new HashMap<ModelElementKey, Collection<TextBlock>>(); private final TextBlockIndex sharedTextBlocksIndex; /** * Create an empty index; */ public TextBlockIndex() { // use empty backing index. this(null); } /** * Create an index with a backing index that will be used as a fallback * if nothing if found within this index. The backing index will never be modified; * * @param sharedTextBlocksIndex */ public TextBlockIndex(TextBlockIndex sharedTextBlocksIndex) { this.sharedTextBlocksIndex = sharedTextBlocksIndex; } /** * Recursively stores the given TextBlock and all its subBlocks within this index. */ public void index(TextBlock textBlock, ConcreteSyntax syntax) { storePerModelElement(textBlock, syntax); if (textBlock.getType() != null) { storePerTemplateAndModelElement(textBlock, syntax); } for (DocumentNode subNode : textBlock.getSubNodes()) { if (subNode instanceof TextBlock) { index((TextBlock) subNode, syntax); } } } private void storePerModelElement(TextBlock textBlock, ConcreteSyntax syntax) { for (EObject correspondingModelElement : textBlock.getCorrespondingModelElements()) { ModelElementKey key = new ModelElementKey(syntax, /*template*/ null, correspondingModelElement); getBlockListForKey(key).add(textBlock); } } private void storePerTemplateAndModelElement(TextBlock textBlock, ConcreteSyntax syntax) { Template template = textBlock.getType(); for (EObject correspondingModelElement : textBlock.getCorrespondingModelElements()) { ModelElementKey key = new ModelElementKey(syntax, template, correspondingModelElement); getBlockListForKey(key).add(textBlock); } } private Collection<TextBlock> getBlockListForKey(ModelElementKey key) { Collection<TextBlock> result = blockIndexPerModelElement.get(key); if (result == null) { result = new ArrayList<TextBlock>(1); blockIndexPerModelElement.put(key, result); } return result; } /** * Returns null if nothing was found. * */ public Collection<TextBlock> findTextBlock(Template template, EObject correspondingModelElement) { Collection<TextBlock> found = null; found = getBlockListForKey(new ModelElementKey(template.getConcreteSyntax(), template, correspondingModelElement)); if (!found.isEmpty()) { return found; } found = getBlockListForKey(new ModelElementKey(template.getConcreteSyntax(), /*template*/ null, correspondingModelElement)); if (!found.isEmpty()) { return found; } // fallback if (sharedTextBlocksIndex == null) { return Collections.emptyList(); } else { return sharedTextBlocksIndex.findTextBlock(template, correspondingModelElement); } } }