### Eclipse Workspace Patch 1.0
#P org.eclipse.gmf.codegen.ui
Index: src/org/eclipse/gmf/internal/codegen/GMFGenConfig.java
===================================================================
RCS file: /cvsroot/technology/org.eclipse.gmf/plugins/org.eclipse.gmf.codegen.ui/src/org/eclipse/gmf/internal/codegen/GMFGenConfig.java,v
retrieving revision 1.11
diff -u -r1.11 GMFGenConfig.java
--- src/org/eclipse/gmf/internal/codegen/GMFGenConfig.java 6 Jun 2006 17:13:01 -0000 1.11
+++ src/org/eclipse/gmf/internal/codegen/GMFGenConfig.java 12 Jun 2006 19:59:22 -0000
@@ -17,6 +17,7 @@
import org.eclipse.gmf.codegen.gmfgen.GMFGenPackage;
import org.eclipse.gmf.codegen.gmfgen.GenChildContainer;
import org.eclipse.gmf.codegen.gmfgen.GenNode;
+import org.eclipse.gmf.internal.common.reconcile.Copier;
import org.eclipse.gmf.internal.common.reconcile.DefaultDecisionMaker;
import org.eclipse.gmf.internal.common.reconcile.Matcher;
import org.eclipse.gmf.internal.common.reconcile.ReconcilerConfigBase;
@@ -57,6 +58,14 @@
preserveIfSet(GMFGEN.getGenDiagram(), GMFGEN.getShortcuts_ShortcutsProvidedFor());
preserveIfSet(GMFGEN.getGenDiagram(), GMFGEN.getEditorCandies_CreationWizardIconPath());
preserveIfSet(GMFGEN.getGenDiagram(), GMFGEN.getGenDiagram_Synchronized());
+ preserveIfSet(GMFGEN.getGenDiagram(), GMFGEN.getBatchValidation_ValidationEnabled());
+ preserveIfSet(GMFGEN.getGenDiagram(), GMFGEN.getBatchValidation_ValidationDecorators());
+ preserveIfSet(GMFGEN.getGenDiagram(), GMFGEN.getBatchValidation_ValidationDecoratorProviderClassName());
+ preserveIfSet(GMFGEN.getGenDiagram(), GMFGEN.getBatchValidation_ValidationDecoratorProviderPriority());
+ preserveIfSet(GMFGEN.getGenDiagram(), GMFGEN.getBatchValidation_ValidationProviderClassName());
+ preserveIfSet(GMFGEN.getGenDiagram(), GMFGEN.getBatchValidation_ValidationProviderPriority());
+ preserveIfSet(GMFGEN.getGenDiagram(), GMFGEN.getBatchValidation_MetricProviderPriority());
+ preserveIfSet(GMFGEN.getGenDiagram(), GMFGEN.getBatchValidation_MetricProviderClassName());
setMatcher(GMFGEN.getGenTopLevelNode(), getGenNodeMatcher());
preserveIfNotByPattern(GMFGEN.getGenTopLevelNode(), GMFGEN.getGenChildContainer_CanonicalEditPolicyClassName(), ".*" + GenChildContainer.CANONICAL_EDIT_POLICY_SUFFIX);
@@ -71,16 +80,16 @@
preserveIfSet(GMFGEN.getGenCompartment(), GMFGEN.getGenCompartment_CanCollapse());
preserveIfSet(GMFGEN.getGenCompartment(), GMFGEN.getGenCompartment_HideIfEmpty());
preserveIfSet(GMFGEN.getGenCompartment(), GMFGEN.getGenCompartment_NeedsTitle());
-
- preserveIfSet(GMFGEN.getGenDiagram(), GMFGEN.getBatchValidation_ValidationEnabled());
- preserveIfSet(GMFGEN.getGenDiagram(), GMFGEN.getBatchValidation_ValidationDecorators());
- preserveIfSet(GMFGEN.getGenDiagram(), GMFGEN.getBatchValidation_ValidationDecoratorProviderClassName());
- preserveIfSet(GMFGEN.getGenDiagram(), GMFGEN.getBatchValidation_ValidationDecoratorProviderPriority());
- preserveIfSet(GMFGEN.getGenDiagram(), GMFGEN.getBatchValidation_ValidationProviderClassName());
- preserveIfSet(GMFGEN.getGenDiagram(), GMFGEN.getBatchValidation_ValidationProviderPriority());
- preserveIfSet(GMFGEN.getGenDiagram(), GMFGEN.getBatchValidation_MetricProviderPriority());
- preserveIfSet(GMFGEN.getGenDiagram(), GMFGEN.getBatchValidation_MetricProviderClassName());
+ //if parent node is matched, then viemap is matched automatically because it is [1] feature.
+ //there are nothing to reconcile for viewmaps, all their properties are derived
+ //we need this only to dig into viewmap attributes
+ setMatcherForAllSubclasses(GMFGEN.getViewmap(), ALWAYS_MATCH);
+
+ setMatcher(GMFGEN.getDefaultSizeAttributes(), ALWAYS_MATCH);
+ setCopier(GMFGEN.getDefaultSizeAttributes(), Copier.COMPLETE_COPY);
+ preserveIfSet(GMFGEN.getDefaultSizeAttributes(), GMFGEN.getDefaultSizeAttributes_Height());
+ preserveIfSet(GMFGEN.getDefaultSizeAttributes(), GMFGEN.getDefaultSizeAttributes_Width());
}
private Matcher getGenNodeMatcher(){
#P org.eclipse.gmf.tests
Index: src/org/eclipse/gmf/tests/gen/CodegenReconcileTest.java
===================================================================
RCS file: /cvsroot/technology/org.eclipse.gmf/tests/org.eclipse.gmf.tests/src/org/eclipse/gmf/tests/gen/CodegenReconcileTest.java,v
retrieving revision 1.11
diff -u -r1.11 CodegenReconcileTest.java
--- src/org/eclipse/gmf/tests/gen/CodegenReconcileTest.java 6 Jun 2006 17:48:30 -0000 1.11
+++ src/org/eclipse/gmf/tests/gen/CodegenReconcileTest.java 12 Jun 2006 19:59:24 -0000
@@ -25,12 +25,16 @@
import org.eclipse.emf.ecore.EStructuralFeature;
import org.eclipse.emf.ecore.EcorePackage;
import org.eclipse.emf.ecore.util.EcoreUtil;
+import org.eclipse.gmf.codegen.gmfgen.Attributes;
+import org.eclipse.gmf.codegen.gmfgen.DefaultSizeAttributes;
+import org.eclipse.gmf.codegen.gmfgen.GMFGenFactory;
import org.eclipse.gmf.codegen.gmfgen.GMFGenPackage;
import org.eclipse.gmf.codegen.gmfgen.GenCompartment;
import org.eclipse.gmf.codegen.gmfgen.GenDiagram;
import org.eclipse.gmf.codegen.gmfgen.GenEditorGenerator;
import org.eclipse.gmf.codegen.gmfgen.GenNode;
import org.eclipse.gmf.codegen.gmfgen.GenPlugin;
+import org.eclipse.gmf.codegen.gmfgen.Viewmap;
import org.eclipse.gmf.internal.codegen.GMFGenConfig;
import org.eclipse.gmf.internal.common.reconcile.DefaultDecisionMaker;
import org.eclipse.gmf.internal.common.reconcile.Reconciler;
@@ -455,6 +459,77 @@
checkUserChange(new EditorChange(GMF.getGenEditorView_ID(), "my.editor.id"));
}
+ public void testReconcileViewmapAttributes(){
+ abstract class AbstractAttributesChange implements UserChange {
+ private int myAffectedViewmapsCount;
+
+ protected abstract Attributes findAttributes(Viewmap viewmap);
+ protected abstract Attributes createUserAttributes();
+ protected abstract void assertChanges(Attributes attributes);
+
+ public final void applyChanges(GenEditorGenerator old) {
+ myAffectedViewmapsCount = 0;
+ for (Iterator allNodes = old.getDiagram().getAllNodes().iterator(); allNodes.hasNext();){
+ GenNode next = (GenNode) allNodes.next();
+ Viewmap nextViewmap = next.getViewmap();
+ if (nextViewmap == null){
+ continue;
+ }
+ Attributes attributes = findAttributes(nextViewmap);
+ assertNull("Reconciler is intended to work with attributes that are created only by user", attributes);
+ attributes = createUserAttributes();
+ nextViewmap.getAttributes().add(attributes);
+ myAffectedViewmapsCount++;
+ }
+ assertTrue(myAffectedViewmapsCount > 0);
+ }
+
+ public final void assertChangesPreserved(GenEditorGenerator current) {
+ int checkedViewmapsCount = 0;
+ for (Iterator allNodes = current.getDiagram().getAllNodes().iterator(); allNodes.hasNext();){
+ GenNode next = (GenNode)allNodes.next();
+ Viewmap nextViewmap = next.getViewmap();
+ if (nextViewmap == null){
+ continue;
+ }
+ Attributes attributes = findAttributes(nextViewmap);
+ assertNotNull(attributes);
+ assertChanges(attributes);
+ checkedViewmapsCount++;
+ }
+ assertEquals(myAffectedViewmapsCount, checkedViewmapsCount);
+ }
+
+ public final ReconcilerConfigBase getReconcilerConfig() {
+ return new GMFGenConfig();
+ }
+ }
+
+ class DefaultSizeChange extends AbstractAttributesChange {
+ private static final int HEIGHT = 23;
+ private static final int WIDTH = 32;
+
+ protected void assertChanges(Attributes attributes) {
+ DefaultSizeAttributes defaultSize = (DefaultSizeAttributes)attributes;
+ assertEquals(HEIGHT, defaultSize.getHeight());
+ assertEquals(WIDTH, defaultSize.getWidth());
+ }
+
+ protected Attributes createUserAttributes() {
+ DefaultSizeAttributes defaultSize = GMFGenFactory.eINSTANCE.createDefaultSizeAttributes();
+ defaultSize.setHeight(HEIGHT);
+ defaultSize.setWidth(WIDTH);
+ return defaultSize;
+ }
+
+ protected Attributes findAttributes(Viewmap viewmap) {
+ return viewmap.find(DefaultSizeAttributes.class);
+ }
+ }
+
+ checkUserChange(new DefaultSizeChange());
+ }
+
private void checkUserChange(UserChange userChange){
GenEditorGenerator old = createCopy();
GenEditorGenerator current = createCopy();
Index: src/org/eclipse/gmf/tests/AllTests.java
===================================================================
RCS file: /cvsroot/technology/org.eclipse.gmf/tests/org.eclipse.gmf.tests/src/org/eclipse/gmf/tests/AllTests.java,v
retrieving revision 1.51
diff -u -r1.51 AllTests.java
--- src/org/eclipse/gmf/tests/AllTests.java 7 Jun 2006 09:52:28 -0000 1.51
+++ src/org/eclipse/gmf/tests/AllTests.java 12 Jun 2006 19:59:23 -0000
@@ -32,6 +32,7 @@
import org.eclipse.gmf.tests.gen.LabelSupportTest;
import org.eclipse.gmf.tests.gen.MapModeStrategyTest;
import org.eclipse.gmf.tests.gen.RTFigureTest;
+import org.eclipse.gmf.tests.gen.ReconcilerPoolTest;
import org.eclipse.gmf.tests.gen.ShapePropertiesTest;
import org.eclipse.gmf.tests.gen.StandaloneMapModeTest;
import org.eclipse.gmf.tests.gen.StandalonePluginConverterTest;
@@ -103,6 +104,7 @@
suite.addTest(feed(AuditRulesTest.class, sessionSetup2));
suite.addTest(feed(ElementInitializerTest.class, sessionSetup2));
suite.addTest(feed(CodegenReconcileTest.class, compartmentsSession));
+ suite.addTestSuite(ReconcilerPoolTest.class);
// fires new runtime workbench initialization
suite.addTestSuite(CompilationTest.class);
Index: src/org/eclipse/gmf/tests/gen/ReconcilerPoolTest.java
===================================================================
RCS file: src/org/eclipse/gmf/tests/gen/ReconcilerPoolTest.java
diff -N src/org/eclipse/gmf/tests/gen/ReconcilerPoolTest.java
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ src/org/eclipse/gmf/tests/gen/ReconcilerPoolTest.java 1 Jan 1970 00:00:00 -0000
@@ -0,0 +1,171 @@
+/*
+ * Copyright (c) 2006 Borland Software Corporation
+ *
+ * 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:
+ * Michael Golubev (Borland) - initial API and implementation
+ */
+
+package org.eclipse.gmf.tests.gen;
+
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+
+import org.eclipse.gmf.internal.common.reconcile.AbstractPool;
+
+import junit.framework.TestCase;
+
+public class ReconcilerPoolTest extends TestCase {
+ public void testMoreAcquiresThanCapacity(){
+ Pool pool = new Pool(2);
+ Object a = pool.acquire();
+ Object b = pool.acquire();
+ Object c = pool.acquire();
+ pool.release(a);
+ pool.release(b);
+ pool.release(c);
+
+ assertEquals(0, pool.getNullsCount());
+ assertEquals(3, pool.getCreationCount());
+ }
+
+ public void testMuchMoreAcquiresGoodShaped(){
+ Pool pool = new Pool(2);
+ Object a = pool.acquire();
+ Object b = pool.acquire();
+
+ final int NOT_POOLED_AQUIRES = 50;
+ for (int i = 0; i < NOT_POOLED_AQUIRES; i++){
+ Object next = pool.acquire();
+ pool.release(next);
+ }
+
+ pool.release(a);
+ pool.release(b);
+
+ assertEquals("When first NOT_POOLED object is release it should be returned to pool", 1 + 2, pool.getCreationCount());
+ assertEquals(0, pool.getNullsCount());
+ }
+
+ public void testImmediateRelease(){
+ Pool pool = new Pool(2);
+ for (int i = 0; i < 50; i++){
+ Object next = pool.acquire();
+ assertEquals(pool.capacity(), pool.getNullsCount());
+ pool.release(next);
+ }
+ assertEquals(1, pool.getCreationCount());
+ assertEquals(pool.capacity() - 1, pool.getNullsCount());
+
+ for (int i = 0; i < 50; i++){
+ Object nextA = pool.acquire();
+ Object nextB = pool.acquire();
+
+ assertEquals(pool.capacity(), pool.getNullsCount());
+
+ if (i % 2 == 0){
+ pool.release(nextA);
+ pool.release(nextB);
+ } else {
+ pool.release(nextB);
+ pool.release(nextA);
+ }
+ }
+
+ assertEquals(2, pool.getCreationCount());
+ assertEquals(pool.capacity() - 2, pool.getNullsCount());
+ }
+
+ public void testBadCase(){
+ Pool pool = new Pool(2);
+ final int ACQUIRES = 50;
+
+ List allAcquired = new LinkedList();
+ for (int i = 0; i < ACQUIRES; i++){
+ allAcquired.add(pool.acquire());
+ }
+ for (Iterator it = allAcquired.iterator(); it.hasNext();){
+ pool.release(it.next());
+ it.remove();
+ }
+ assertEquals(ACQUIRES, pool.getCreationCount());
+ assertEquals(0, pool.getNullsCount());
+
+ //once again
+ for (int i = 0; i < ACQUIRES; i++){
+ allAcquired.add(pool.acquire());
+ }
+ for (Iterator it = allAcquired.iterator(); it.hasNext();){
+ pool.release(it.next());
+ it.remove();
+ }
+
+ assertEquals(ACQUIRES * 2 - pool.capacity(), pool.getCreationCount());
+ assertEquals(0, pool.getNullsCount());
+ }
+
+ public void testBaseInternals(){
+ Pool pool = new Pool(2);
+ Object a = pool.acquire();
+ assertEquals(1, pool.getCreationCount());
+ assertEquals(2, pool.getNullsCount());
+
+ pool.release(a);
+ assertEquals(1, pool.getCreationCount());
+ assertEquals(1, pool.getNullsCount());
+
+ Object aa = pool.acquire();
+ assertEquals(1, pool.getCreationCount());
+ assertEquals(2, pool.getNullsCount());
+ assertSame(a, aa);
+
+ Object b = pool.acquire();
+ assertEquals(2, pool.getCreationCount());
+ assertEquals(2, pool.getNullsCount());
+ assertNotSame(a, b);
+
+ pool.release(a);
+ assertEquals(2, pool.getCreationCount());
+ assertEquals(1, pool.getNullsCount());
+
+ pool.release(b);
+ assertEquals(2, pool.getCreationCount());
+ assertEquals(0, pool.getNullsCount());
+ }
+
+ private static class Pool extends AbstractPool {
+ private int myCreationCount;
+
+ public Pool(int capacity) {
+ super(capacity);
+ }
+
+ protected Object createNew() {
+ myCreationCount++;
+ return new Object();
+ }
+
+ public Object acquire(){
+ Object result = internalAcquire();
+ assertNotNull(result);
+ return result;
+ }
+
+ public void release(Object object){
+ internalRelease(object);
+ }
+
+ public int getCreationCount() {
+ return myCreationCount;
+ }
+
+ public int getNullsCount() {
+ return internalCountNulls();
+ }
+ }
+}
#P org.eclipse.gmf.common
Index: src/org/eclipse/gmf/internal/common/reconcile/Reconciler.java
===================================================================
RCS file: /cvsroot/technology/org.eclipse.gmf/plugins/org.eclipse.gmf.common/src/org/eclipse/gmf/internal/common/reconcile/Reconciler.java,v
retrieving revision 1.2
diff -u -r1.2 Reconciler.java
--- src/org/eclipse/gmf/internal/common/reconcile/Reconciler.java 15 Mar 2006 15:16:59 -0000 1.2
+++ src/org/eclipse/gmf/internal/common/reconcile/Reconciler.java 12 Jun 2006 19:59:25 -0000
@@ -12,18 +12,36 @@
package org.eclipse.gmf.internal.common.reconcile;
+import java.util.ArrayList;
import java.util.Collection;
+import java.util.HashSet;
import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
import org.eclipse.emf.ecore.EClass;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.resource.Resource;
public class Reconciler {
+ /**
+ * Expected max breadth of the node in the reconciled tree
+ */
+ private static final int PAIRS_POOL_SIZE = 100;
+
+ /**
+ * Expected depth of the reconciled tree
+ */
+ private static final int STORAGE_POOL_SIZE = 10;
+
private final ReconcilerConfig myConfig;
+ private final MatchingSession myMatchingSession;
+ private final StoragePool myStoragePool;
public Reconciler(ReconcilerConfig config){
myConfig = config;
+ myMatchingSession = new MatchingSession(new PairsPool(PAIRS_POOL_SIZE));
+ myStoragePool = new StoragePool(STORAGE_POOL_SIZE);
}
protected void handleNotMatchedCurrent(EObject current){
@@ -31,13 +49,18 @@
//FIXME How to handle not macthed old ???
}
+ protected EObject handleNotMatchedOld(EObject currentParent, EObject notMatchedOld) {
+ Copier copier = myConfig.getCopier(notMatchedOld.eClass());
+ return copier.copyToCurrent(currentParent, notMatchedOld);
+ }
+
public void reconcileResource(Resource current, Resource old){
- reconcileContents(current.getContents(), old.getContents());
+ reconcileContents(null, current.getContents(), old.getContents());
}
public void reconcileTree(EObject currentRoot, EObject oldRoot){
reconcileVertex(currentRoot, oldRoot);
- reconcileContents(currentRoot.eContents(), oldRoot.eContents());
+ reconcileContents(currentRoot, currentRoot.eContents(), oldRoot.eContents());
}
private void reconcileVertex(EObject current, EObject old){
@@ -50,31 +73,159 @@
}
}
- private void reconcileContents(Collection allCurrents, Collection allOlds){
- for (Iterator currentContents = allCurrents.iterator(); currentContents.hasNext();){
- EObject nextCurrent = (EObject) currentContents.next();
- EObject nextOld = findMatched(nextCurrent, allOlds);
- if (nextOld == null){
- handleNotMatchedCurrent(nextCurrent);
- } else {
+ private void reconcileContents(EObject currentParent, Collection allCurrents, Collection allOlds){
+ if (allCurrents.isEmpty() && allOlds.isEmpty()){
+ return;
+ }
+ List storage = myStoragePool.acquireList();
+ myMatchingSession.match(allCurrents, allOlds, storage);
+
+ for (Iterator pairs = storage.iterator(); pairs.hasNext();){
+ Pair next = (Pair)pairs.next();
+ EObject nextCurrent = next.current;
+ EObject nextOld = next.old;
+ assert (nextCurrent != null || nextOld != null);
+
+ myMatchingSession.releasePair(next);
+
+ if (nextCurrent == null){
+ if (currentParent != null){ //never copy top-level resource contents
+ nextCurrent = handleNotMatchedOld(currentParent, nextOld);
+ }
+ }
+
+ if (nextCurrent != null && nextOld != null){
reconcileTree(nextCurrent, nextOld);
+ } else if (nextOld == null){
+ handleNotMatchedCurrent(nextCurrent);
}
}
+ myStoragePool.release(storage);
}
- private EObject findMatched(EObject current, Collection allOld){
- EClass eClass = current.eClass();
- Matcher matcher = myConfig.getMatcher(eClass);
- EObject result = null;
- if (matcher != Matcher.FALSE){
- for (Iterator all = allOld.iterator(); result == null && all.hasNext();){
- EObject next = (EObject)all.next();
- if (eClass.equals(next.eClass()) && matcher.match(current, next)){
- result = next;
+ private static class Pair {
+ public EObject current;
+ public EObject old;
+
+ public void reset(){
+ current = null;
+ old = null;
+ }
+ }
+
+ private class MatchingSession {
+ private final Collection myCurrents;
+ private final Collection myOlds;
+ private final PairsPool myPool;
+ private boolean myIsMatching;
+
+ public MatchingSession(PairsPool pool){
+ myPool = pool;
+ myCurrents = new LinkedList();
+ myOlds = new HashSet();
+ }
+
+ public void match(Collection currents, Collection olds, Collection output){
+ assert !myIsMatching;
+ assert myOlds.isEmpty();
+ assert myCurrents.isEmpty();
+
+ if (myIsMatching){
+ throw new IllegalStateException("FIXME: remove me");
+ }
+
+ try {
+ myIsMatching = true;
+
+ myCurrents.addAll(currents);
+ myOlds.addAll(olds);
+
+ for (Iterator currentContents = myCurrents.iterator(); !myOlds.isEmpty() && currentContents.hasNext();){
+ EObject nextCurrent = (EObject) currentContents.next();
+ Pair nextPair = acquirePair();
+ nextPair.current = nextCurrent;
+ nextPair.old = removeMatched(nextCurrent, myOlds);
+ output.add(nextPair);
+ currentContents.remove();
+ }
+
+ for (Iterator notMatchedOlds = myOlds.iterator(); notMatchedOlds.hasNext();){
+ Pair nextPair = acquirePair();
+ nextPair.current = null;
+ nextPair.old = (EObject)notMatchedOlds.next();
+ output.add(nextPair);
}
+ } finally {
+ myIsMatching = false;
+ myCurrents.clear();
+ myOlds.clear();
}
}
- return result;
+
+ private EObject removeMatched(EObject current, Collection allOld){
+ EClass eClass = current.eClass();
+ Matcher matcher = myConfig.getMatcher(eClass);
+ EObject result = null;
+ if (matcher != Matcher.FALSE){
+ for (Iterator all = allOld.iterator(); all.hasNext();){
+ EObject next = (EObject)all.next();
+ if (eClass.equals(next.eClass()) && matcher.match(current, next)){
+ result = next;
+ all.remove();
+ break;
+ }
+ }
+ }
+ return result;
+ }
+
+ private Pair acquirePair(){
+ return myPool.acquire();
+ }
+
+ public void releasePair(Pair pair){
+ myPool.release(pair);
+ }
+
+ }
+
+ private static class PairsPool extends AbstractPool {
+ public PairsPool(int capacity) {
+ super(capacity);
+ }
+
+ public Pair acquire(){
+ return (Pair)internalAcquire();
+ }
+
+ public void release(Pair pair){
+ pair.current = null;
+ pair.old = null;
+ internalRelease(pair);
+ }
+
+ protected Object createNew() {
+ return new Pair();
+ }
+ }
+
+ private static class StoragePool extends AbstractPool {
+ public StoragePool(int capacity){
+ super(capacity);
+ }
+
+ public List acquireList(){
+ return (List)internalAcquire();
+ }
+
+ public void release(List list){
+ list.clear();
+ internalRelease(list);
+ }
+
+ protected Object createNew() {
+ return new ArrayList();
+ }
}
}
Index: src/org/eclipse/gmf/internal/common/reconcile/ReconcilerConfigBase.java
===================================================================
RCS file: /cvsroot/technology/org.eclipse.gmf/plugins/org.eclipse.gmf.common/src/org/eclipse/gmf/internal/common/reconcile/ReconcilerConfigBase.java,v
retrieving revision 1.2
diff -u -r1.2 ReconcilerConfigBase.java
--- src/org/eclipse/gmf/internal/common/reconcile/ReconcilerConfigBase.java 15 Mar 2006 15:16:59 -0000 1.2
+++ src/org/eclipse/gmf/internal/common/reconcile/ReconcilerConfigBase.java 12 Jun 2006 19:59:25 -0000
@@ -14,6 +14,7 @@
import java.text.MessageFormat;
import java.util.HashMap;
+import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
@@ -25,15 +26,21 @@
public class ReconcilerConfigBase implements ReconcilerConfig {
private static final EClassRecord EMPTY_RECORD = new EClassRecord();
private final HashMap myEClass2Record;
+ private final HashMap myAbstractEClass2SubclassesRecord;
public ReconcilerConfigBase(){
myEClass2Record = new HashMap();
+ myAbstractEClass2SubclassesRecord = new HashMap();
}
public final Matcher getMatcher(EClass eClass) {
return getRecord(eClass, false).getMatcher();
}
+ public Copier getCopier(EClass eClass) {
+ return getRecord(eClass, false).getCopier();
+ }
+
public final DecisionMaker[] getDecisionMakers(EClass eClass) {
return getRecord(eClass, false).getDecisionMakers();
}
@@ -42,6 +49,19 @@
getRecord(eClass, true).setMatcher(matcher);
}
+ protected final void setCopier(EClass eClass, Copier copier){
+ getRecord(eClass, true).setCopier(copier);
+ }
+
+ protected final void setMatcherForAllSubclasses(EClass eClass, Matcher matcher){
+ if (!eClass.isAbstract()){
+ throw new IllegalArgumentException(
+ "This is not safe method that may lead to strange behaviour in case of multiple inheritance. " +
+ "We tried to limit its usage as much as possible");
+ }
+ getTemplateRecord(eClass, true).setMatcher(matcher);
+ }
+
protected final void addDecisionMaker(EClass eClass, DecisionMaker decisionMaker){
getRecord(eClass, true).addDecisionMaker(decisionMaker);
}
@@ -69,11 +89,29 @@
myEClass2Record.put(eClass, result);
} else {
result = EMPTY_RECORD;
+ for (Iterator superClasses = eClass.getEAllSuperTypes().iterator(); result == EMPTY_RECORD && superClasses.hasNext();){
+ EClass nextSuper = (EClass) superClasses.next();
+ result = getTemplateRecord(nextSuper, false);
+ }
+ if (result != EMPTY_RECORD){
+ //cache it for the next time
+ myEClass2Record.put(eClass, result);
+ }
}
}
return result;
}
+ private EClassRecord getTemplateRecord(EClass abstractSuperClass, boolean force){
+ assert abstractSuperClass.isAbstract();
+ EClassRecord result = (EClassRecord)myAbstractEClass2SubclassesRecord.get(abstractSuperClass);
+ if (result == null && force){
+ result = new EClassRecord();
+ myAbstractEClass2SubclassesRecord.put(abstractSuperClass, result);
+ }
+ return result == null ? EMPTY_RECORD : result;
+ }
+
private void checkStructuralFeature(EClass expectedClass, EAttribute feature) {
if (expectedClass.getEStructuralFeature(feature.getFeatureID()) != feature){
throw new IllegalArgumentException(MessageFormat.format("Alien feature {0} for EClass {1}", new Object[] {feature, expectedClass}));
@@ -88,6 +126,7 @@
private static class EClassRecord {
private Matcher myMatcher = Matcher.FALSE;
+ private Copier myCopier = Copier.NEVER_COPY;
private final List myDecisionMakers = new LinkedList();
private DecisionMaker[] myMakersArray;
@@ -96,6 +135,10 @@
makersSetChanged();
}
+ public void setCopier(Copier copier) {
+ myCopier = copier;
+ }
+
public DecisionMaker[] getDecisionMakers(){
if (myMakersArray == null){
myMakersArray = (DecisionMaker[]) myDecisionMakers.toArray(new DecisionMaker[myDecisionMakers.size()]);
@@ -111,6 +154,10 @@
return myMatcher;
}
+ public Copier getCopier() {
+ return myCopier;
+ }
+
private void makersSetChanged(){
myMakersArray = null;
}
Index: src/org/eclipse/gmf/internal/common/reconcile/ReconcilerConfig.java
===================================================================
RCS file: /cvsroot/technology/org.eclipse.gmf/plugins/org.eclipse.gmf.common/src/org/eclipse/gmf/internal/common/reconcile/ReconcilerConfig.java,v
retrieving revision 1.1
diff -u -r1.1 ReconcilerConfig.java
--- src/org/eclipse/gmf/internal/common/reconcile/ReconcilerConfig.java 13 Mar 2006 12:02:47 -0000 1.1
+++ src/org/eclipse/gmf/internal/common/reconcile/ReconcilerConfig.java 12 Jun 2006 19:59:25 -0000
@@ -17,4 +17,5 @@
public interface ReconcilerConfig {
Matcher getMatcher(EClass eClass);
DecisionMaker[] getDecisionMakers(EClass eClass);
+ Copier getCopier(EClass eClass);
}
Index: src/org/eclipse/gmf/internal/common/reconcile/Copier.java
===================================================================
RCS file: src/org/eclipse/gmf/internal/common/reconcile/Copier.java
diff -N src/org/eclipse/gmf/internal/common/reconcile/Copier.java
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ src/org/eclipse/gmf/internal/common/reconcile/Copier.java 1 Jan 1970 00:00:00 -0000
@@ -0,0 +1,82 @@
+/*
+ * Copyright (c) 2006 Borland Software Corporation
+ *
+ * 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:
+ * Michael Golubev (Borland) - initial API and implementation
+ */
+
+package org.eclipse.gmf.internal.common.reconcile;
+
+import java.util.Collection;
+import java.util.Collections;
+
+import org.eclipse.emf.ecore.EClass;
+import org.eclipse.emf.ecore.EObject;
+import org.eclipse.emf.ecore.EStructuralFeature;
+import org.eclipse.emf.ecore.util.EcoreUtil;
+
+public interface Copier {
+ /**
+ * Copies relevant content of the old object into the current ancestor.
+ *
+ * @param currentParent
+ * the parent node in the current tree. It is guarranteed that
+ * parent was matched with old.eContainer()
+ * @param old
+ * the element found in the old tree which does not have matched
+ * element in the current tree
+ * @return just created element copied into the current tree or
+ * null
if copier decided to avoid creation of
+ * element.
+ *
+ * NOTE: in case if this method returns true, result is considered as
+ * "matched" with old
automatically, without any further
+ * matchings
+ */
+ public EObject copyToCurrent(EObject currentParent, EObject old);
+
+ public static final Copier NEVER_COPY = new Copier(){
+ public EObject copyToCurrent(EObject currentParent, EObject old) {
+ return null;
+ }
+ };
+
+ public static final Copier COMPLETE_COPY = new Copier(){
+
+ public EObject copyToCurrent(EObject currentParent, EObject old) {
+ safetyCheck(old);
+ EClass currentParentEClass = currentParent.eClass();
+ EObject oldParent = old.eContainer();
+ EClass oldParentEClass = oldParent.eClass();
+ EObject currentCopy = null;
+ if (currentParentEClass.equals(oldParentEClass)){
+ currentCopy = EcoreUtil.copy(old);
+ EStructuralFeature containment = old.eContainingFeature();
+ Object currentValue = currentParent.eGet(containment);
+ if (currentValue instanceof Collection){
+ ((Collection)currentValue).add(currentCopy);
+ } else {
+ currentParent.eSet(containment, currentCopy);
+ }
+ }
+ return currentCopy;
+ }
+
+ /**
+ * It is not trivial to copy the external references in the context of
+ * reconilation. If you need this, do not use this simple implementation.
+ */
+ private void safetyCheck(EObject old){
+ if (!EcoreUtil.CrossReferencer.find(Collections.singleton(old)).isEmpty()){
+ throw new IllegalArgumentException("I am not intended to copy elements woth cross references");
+ }
+ }
+
+ };
+
+}
Index: src/org/eclipse/gmf/internal/common/reconcile/AbstractPool.java
===================================================================
RCS file: src/org/eclipse/gmf/internal/common/reconcile/AbstractPool.java
diff -N src/org/eclipse/gmf/internal/common/reconcile/AbstractPool.java
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ src/org/eclipse/gmf/internal/common/reconcile/AbstractPool.java 1 Jan 1970 00:00:00 -0000
@@ -0,0 +1,64 @@
+/*
+ * Copyright (c) 2006 Borland Software Corporation
+ *
+ * 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:
+ * Michael Golubev (Borland) - initial API and implementation
+ */
+
+package org.eclipse.gmf.internal.common.reconcile;
+
+public abstract class AbstractPool {
+ private final Object[] myPairs;
+ private int myNextIndex;
+
+ protected abstract Object createNew();
+
+ public AbstractPool(int capacity){
+ myPairs = new Object[capacity];
+ }
+
+ public final int capacity(){
+ return myPairs.length;
+ }
+
+ protected final Object internalAcquire(){
+ Object result = null;
+ if (myNextIndex < myPairs.length){
+ result = myPairs[myNextIndex];
+ myPairs[myNextIndex] = null;
+ myNextIndex++;
+ }
+ if (result == null){
+ result = createNew();
+ }
+ return result;
+ }
+
+ protected final void internalRelease(Object pair){
+ if (myNextIndex > 0){
+ myNextIndex--;
+ if (myPairs[myNextIndex] != null){
+ throw new IllegalStateException("FIXME: should be assert here");
+ }
+ myPairs[myNextIndex] = pair;
+ }
+ }
+
+ /**
+ * For testing purposes only
+ */
+ protected final int internalCountNulls(){
+ int result = 0;
+ for (int i = 0; i < myPairs.length; i++){
+ if (myPairs[i] == null){
+ result++;
+ }
+ }
+ return result;
+ }
+}