Skip to main content
aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChristian W. Damus2013-09-06 15:37:34 +0000
committerChristian W. Damus2013-09-16 20:02:46 +0000
commit2a36cf4f54847aa650eed9eb00d552e8fa3fc1c4 (patch)
tree5093302e04d03f355d2666f1ccbbe01b689966d2 /extraplugins
parent78b304cdae37ac7195af173414ad2661a7a8ac6a (diff)
downloadorg.eclipse.papyrus-2a36cf4f54847aa650eed9eb00d552e8fa3fc1c4.tar.gz
org.eclipse.papyrus-2a36cf4f54847aa650eed9eb00d552e8fa3fc1c4.tar.xz
org.eclipse.papyrus-2a36cf4f54847aa650eed9eb00d552e8fa3fc1c4.zip
415369: [CDO] Support controlled resources and lazy loading
https://bugs.eclipse.org/bugs/show_bug.cgi?id=415369 Ensure on save that new/changed cross-unit references use the proper lazy-loading proxies.
Diffstat (limited to 'extraplugins')
-rw-r--r--extraplugins/cdo/org.eclipse.papyrus.cdo.core/src/org/eclipse/papyrus/cdo/core/resource/CDOAwareModelSet.java77
-rw-r--r--extraplugins/cdo/org.eclipse.papyrus.cdo.core/src/org/eclipse/papyrus/cdo/internal/core/CDOUtils.java145
-rw-r--r--extraplugins/cdo/org.eclipse.papyrus.cdo.core/src/org/eclipse/papyrus/cdo/internal/core/controlmode/CDOControlModeParticipant.java26
3 files changed, 238 insertions, 10 deletions
diff --git a/extraplugins/cdo/org.eclipse.papyrus.cdo.core/src/org/eclipse/papyrus/cdo/core/resource/CDOAwareModelSet.java b/extraplugins/cdo/org.eclipse.papyrus.cdo.core/src/org/eclipse/papyrus/cdo/core/resource/CDOAwareModelSet.java
index c3fb05d993c..4725713ad04 100644
--- a/extraplugins/cdo/org.eclipse.papyrus.cdo.core/src/org/eclipse/papyrus/cdo/core/resource/CDOAwareModelSet.java
+++ b/extraplugins/cdo/org.eclipse.papyrus.cdo.core/src/org/eclipse/papyrus/cdo/core/resource/CDOAwareModelSet.java
@@ -12,10 +12,14 @@
package org.eclipse.papyrus.cdo.core.resource;
import java.io.IOException;
+import java.util.Collection;
import java.util.Collections;
import java.util.EnumSet;
import java.util.Set;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.SubMonitor;
+import org.eclipse.emf.cdo.CDOObject;
import org.eclipse.emf.cdo.CDOState;
import org.eclipse.emf.cdo.dawn.gmf.util.DawnDiagramUpdater;
import org.eclipse.emf.cdo.eresource.CDOResource;
@@ -29,6 +33,7 @@ import org.eclipse.emf.common.notify.Adapter;
import org.eclipse.emf.common.util.EList;
import org.eclipse.emf.common.util.URI;
import org.eclipse.emf.ecore.EObject;
+import org.eclipse.emf.ecore.EReference;
import org.eclipse.emf.ecore.resource.Resource;
import org.eclipse.emf.transaction.TransactionalEditingDomain;
import org.eclipse.gmf.runtime.notation.Diagram;
@@ -37,12 +42,14 @@ import org.eclipse.net4j.util.event.IListener;
import org.eclipse.papyrus.cdo.core.IPapyrusRepository;
import org.eclipse.papyrus.cdo.core.IPapyrusRepositoryManager;
import org.eclipse.papyrus.cdo.internal.core.CDOUtils;
+import org.eclipse.papyrus.cdo.internal.core.controlmode.CDOControlModeParticipant;
import org.eclipse.papyrus.cdo.internal.core.controlmode.CDOProxyManager;
import org.eclipse.papyrus.infra.core.Activator;
import org.eclipse.papyrus.infra.core.resource.ModelMultiException;
import org.eclipse.papyrus.infra.services.resourceloading.OnDemandLoadingModelSet;
import com.google.common.base.Predicates;
+import com.google.common.collect.ImmutableList;
import com.google.common.collect.Iterables;
/**
@@ -177,21 +184,21 @@ public class CDOAwareModelSet extends OnDemandLoadingModelSet {
try {
super.unload();
} finally {
- if((repository != null) && (getCDOView() != null)) {
- CDOView view = getCDOView();
- if(view != null) {
- view.removeListener(getInvalidationListener());
- }
- invalidationListener = null;
+ if((repository != null) && (getCDOView() != null)) {
+ CDOView view = getCDOView();
+ if(view != null) {
+ view.removeListener(getInvalidationListener());
+ }
+ invalidationListener = null;
- // dispose the transaction
- repository.close(this);
+ // dispose the transaction
+ repository.close(this);
// now, we can remove the CDOViewSet adapter
eAdapters().clear();
- }
+ }
- repository = null;
+ repository = null;
}
}
@@ -330,6 +337,56 @@ public class CDOAwareModelSet extends OnDemandLoadingModelSet {
return result;
}
+ @Override
+ public void save(IProgressMonitor monitor) throws IOException {
+ CDOView view = getCDOView();
+ CDOTransaction transaction = null;
+
+ Collection<CDOObject> updates;
+ if((view instanceof CDOTransaction) && view.isDirty()) {
+ // collect updated objects to post-process for cross-unit references
+ transaction = (CDOTransaction)view;
+ updates = ImmutableList.<CDOObject> builder() //
+ .addAll(transaction.getNewObjects().values()) //
+ .addAll(transaction.getDirtyObjects().values()) //
+ .build();
+ } else {
+ updates = Collections.emptyList();
+ }
+
+ SubMonitor sub = SubMonitor.convert(monitor, updates.isEmpty() ? 1 : 2);
+
+ super.save(sub.newChild(1));
+
+ if(!updates.isEmpty()) {
+ CDOControlModeParticipant control = new CDOControlModeParticipant();
+ CDOControlModeParticipant.IUpdate run = CDOControlModeParticipant.IUpdate.EMPTY;
+
+ for(CDOObject next : updates) {
+ EObject object = CDOUtil.getEObject(next);
+ if(object != null) {
+ for(EReference xref : object.eClass().getEAllReferences()) {
+ if(!xref.isContainment() && xref.isChangeable() && !xref.isDerived() && !xref.isTransient()) {
+ run = run.chain(control.getProxyCrossReferencesUpdate(object, xref));
+ }
+ }
+ }
+ }
+
+ if(!run.isEmpty()) {
+ run.apply();
+
+ try {
+ transaction.commit(sub.newChild(1));
+ } catch (CommitException e) {
+ Activator.log.error("Follow-up commit after save failed.", e);
+ }
+ } else {
+ sub.done();
+ }
+ }
+ }
+
//
// Nested types
//
diff --git a/extraplugins/cdo/org.eclipse.papyrus.cdo.core/src/org/eclipse/papyrus/cdo/internal/core/CDOUtils.java b/extraplugins/cdo/org.eclipse.papyrus.cdo.core/src/org/eclipse/papyrus/cdo/internal/core/CDOUtils.java
index 02b97de7bc0..0c021b6f628 100644
--- a/extraplugins/cdo/org.eclipse.papyrus.cdo.core/src/org/eclipse/papyrus/cdo/internal/core/CDOUtils.java
+++ b/extraplugins/cdo/org.eclipse.papyrus.cdo.core/src/org/eclipse/papyrus/cdo/internal/core/CDOUtils.java
@@ -14,6 +14,8 @@ package org.eclipse.papyrus.cdo.internal.core;
import static com.google.common.collect.Iterables.filter;
import static com.google.common.collect.Iterables.getFirst;
+import java.util.ListIterator;
+import java.util.NoSuchElementException;
import java.util.Set;
import java.util.concurrent.Executor;
@@ -32,11 +34,14 @@ import org.eclipse.emf.cdo.view.CDOViewSet;
import org.eclipse.emf.common.notify.Notifier;
import org.eclipse.emf.common.util.URI;
import org.eclipse.emf.ecore.EObject;
+import org.eclipse.emf.ecore.EReference;
import org.eclipse.emf.ecore.EStructuralFeature;
import org.eclipse.emf.ecore.resource.Resource;
import org.eclipse.emf.ecore.resource.ResourceSet;
+import org.eclipse.emf.ecore.util.EContentsEList.FeatureListIterator;
import org.eclipse.emf.ecore.util.ECrossReferenceAdapter;
import org.eclipse.emf.ecore.util.EcoreUtil;
+import org.eclipse.emf.ecore.util.InternalEList;
import org.eclipse.emf.edit.domain.EditingDomain;
import org.eclipse.emf.transaction.ResourceSetChangeEvent;
import org.eclipse.emf.transaction.TransactionalEditingDomain;
@@ -45,6 +50,7 @@ import org.eclipse.papyrus.cdo.core.util.CDOFunctions;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Iterables;
+import com.google.common.collect.UnmodifiableListIterator;
/**
* This is the CDOUtils type. Enjoy.
@@ -225,6 +231,145 @@ public class CDOUtils {
}
/**
+ * Obtains an unmodifiable iterator over the values in the specified {@code feature} of an {@code object}. The resulting iterator supplies zero
+ * or one element for scalar features, according to whether the feature's value is {@code null} or not. In the case of a scalar feature,
+ * the index of the element as reported by {@link ListIterator#nextIndex()} and {@link ListIterator#previousIndex()} is {@code -1}.
+ *
+ * @param object
+ * an object
+ * @param feature
+ * a feature of the {@code object}
+ * @param resolve
+ * whether to resolve proxies (in the case of an {@link EReference}
+ *
+ * @return the unmodifiable feature list iterator
+ */
+ public static <E> FeatureListIterator<E> iterator(EObject object, final EStructuralFeature feature, boolean resolve) {
+ FeatureListIterator<E> result;
+
+ Object value = object.eGet(feature, resolve);
+ if(value instanceof InternalEList<?>) {
+ @SuppressWarnings("unchecked")
+ InternalEList<E> list = (InternalEList<E>)value;
+ final ListIterator<E> delegate = (resolve) ? list.listIterator() : list.basicListIterator();
+
+ class NonEmpty extends UnmodifiableListIterator<E> implements FeatureListIterator<E> {
+
+ public EStructuralFeature feature() {
+ return feature;
+ }
+
+ public boolean hasNext() {
+ return delegate.hasNext();
+ }
+
+ public E next() {
+ return delegate.next();
+ }
+
+ public int nextIndex() {
+ return delegate.nextIndex();
+ }
+
+ public boolean hasPrevious() {
+ return delegate.hasPrevious();
+ }
+
+ public E previous() {
+ return delegate.previous();
+ }
+
+ public int previousIndex() {
+ return delegate.previousIndex();
+ }
+ };
+
+ result = new NonEmpty();
+ } else if(value == null) {
+ class Empty extends UnmodifiableListIterator<E> implements FeatureListIterator<E> {
+
+ public EStructuralFeature feature() {
+ return feature;
+ }
+
+ public boolean hasNext() {
+ return false;
+ }
+
+ public E next() {
+ throw new NoSuchElementException();
+ }
+
+ public int nextIndex() {
+ return -1;
+ }
+
+ public boolean hasPrevious() {
+ return false;
+ }
+
+ public E previous() {
+ throw new NoSuchElementException();
+ }
+
+ public int previousIndex() {
+ return -2;
+ }
+ };
+
+ result = new Empty();
+ } else {
+ @SuppressWarnings("unchecked")
+ final E onlyValue = (E)value;
+
+ class Singleton extends UnmodifiableListIterator<E> implements FeatureListIterator<E> {
+
+ private int index = -1;
+
+ public EStructuralFeature feature() {
+ return feature;
+ }
+
+ public boolean hasNext() {
+ return index < 0;
+ }
+
+ public E next() {
+ if(!hasNext()) {
+ throw new NoSuchElementException();
+ }
+ index++;
+ return onlyValue;
+ }
+
+ public int nextIndex() {
+ return index;
+ }
+
+ public boolean hasPrevious() {
+ return index == 0;
+ }
+
+ public E previous() {
+ if(!hasPrevious()) {
+ throw new NoSuchElementException();
+ }
+ index--;
+ return onlyValue;
+ }
+
+ public int previousIndex() {
+ return index - 1;
+ }
+ };
+
+ result = new Singleton();
+ }
+
+ return result;
+ }
+
+ /**
* <p>
* Runs a code block that broadcasts notification of {@link ResourceSetChangeEvent}s, {@link CDOViewInvalidationEvent}s, etc. to listeners using
* the most appropriate {@linkplain #setBroadcastExecutor() executor} available. This allows a UI-safe execution to be injected if necessary.
diff --git a/extraplugins/cdo/org.eclipse.papyrus.cdo.core/src/org/eclipse/papyrus/cdo/internal/core/controlmode/CDOControlModeParticipant.java b/extraplugins/cdo/org.eclipse.papyrus.cdo.core/src/org/eclipse/papyrus/cdo/internal/core/controlmode/CDOControlModeParticipant.java
index 47d73b54142..ee6563e87ae 100644
--- a/extraplugins/cdo/org.eclipse.papyrus.cdo.core/src/org/eclipse/papyrus/cdo/internal/core/controlmode/CDOControlModeParticipant.java
+++ b/extraplugins/cdo/org.eclipse.papyrus.cdo.core/src/org/eclipse/papyrus/cdo/internal/core/controlmode/CDOControlModeParticipant.java
@@ -14,6 +14,7 @@ package org.eclipse.papyrus.cdo.internal.core.controlmode;
import static com.google.common.collect.Iterables.concat;
import static com.google.common.collect.Iterables.filter;
import static com.google.common.collect.Iterables.transform;
+import static org.eclipse.papyrus.cdo.internal.core.controlmode.CDOProxyManager.createPapyrusCDOURI;
import java.util.Collections;
import java.util.EnumSet;
@@ -139,6 +140,31 @@ public class CDOControlModeParticipant implements IControlCommandParticipant, IU
}
}
+ public IUpdate getProxyCrossReferencesUpdate(final EObject owner, final EReference crossReference) {
+ IUpdate result = IUpdate.EMPTY;
+ final CDOStore[] store = { null };
+
+ for(ListIterator<? extends EObject> xrefs = CDOUtils.iterator(owner, crossReference, false); xrefs.hasNext();) {
+ final int index = xrefs.nextIndex();
+ final EObject referent = xrefs.next();
+
+ if(!referent.eIsProxy() && !inSameUnit(owner, referent)) {
+ if(store[0] == null) {
+ store[0] = ((InternalCDOView)CDOUtils.getCDOObject(owner).cdoView()).getStore();
+ }
+
+ result = result.chain(new OneWayUpdate() {
+
+ public void apply() {
+ store[0].set((InternalEObject)owner, crossReference, index, CDOIDUtil.createExternal(createPapyrusCDOURI(referent)));
+ }
+ });
+ }
+ }
+
+ return result;
+ }
+
public ICommand getPreUncontrolCommand(ControlModeRequest request) {
return new AbstractCDOControlCommand(request) {

Back to the top