public void cdoInternalPostDetach(boolean remote) { if (remote) { setInstanceContainer(null, eContainerFeatureID()); setInstanceResource(null); return; } // This loop adjusts the opposite wrapper objects to support dangling references. See // Bugzilla_251263_Test InternalCDORevision revision = cdoRevision(); for (EReference reference : classInfo.getAllPersistentReferences()) { if (!reference.isContainer() && classInfo.hasPersistentOpposite(reference)) { if (reference.isMany()) { EReference oppositeReference = reference.getEOpposite(); int size = revision.size(reference); for (int i = 0; i < size; i++) { EObject object = (EObject) getValueFromRevision(reference, i); adjustPersistentOppositeReference(this, object, oppositeReference); } } else { EObject oppositeObject = (EObject) instance.eGet(reference); if (oppositeObject != null) { EReference oppositeReference = reference.getEOpposite(); adjustPersistentOppositeReference(this, oppositeObject, oppositeReference); } } } } }
/** TODO Consider using only EMF concepts for resolving proxies! */ protected void resolveAllProxies() { for (EStructuralFeature feature : classInfo.getAllPersistentFeatures()) { if (feature instanceof EReference) { resolveProxies(feature); } } }
/** * CDO persists the isUnset state of an eObject in the database. The indicator for this is that * the feature is null in the revision (see CDOStore.isSet()). When committing a legacy object all * values in the instance for native attributes are set with the java default values. So, these * values will be stored in the revision and CDO cannot distinguish whether the feature is set or * not. This method must ensure that the value will be set to null if the feature is not set. */ public void cdoInternalPreCommit() { // We have to set this here because the CDOLegacyAdapter will not be notified when the instance // is the target of a // single-directional containment reference. // If the container is not an legacy Object the system will get no information instanceToRevisionContainment(); InternalCDORevision revision = cdoRevision(); for (EStructuralFeature feature : classInfo.getAllPersistentFeatures()) { if (feature.isUnsettable()) { if (!isSetInstanceValue(instance, feature)) { if (feature.isMany()) { @SuppressWarnings("unchecked") InternalEList<Object> list = (InternalEList<Object>) instance.eGet(feature); clearEList(list); } else { revision.set(feature, EStore.NO_INDEX, null); } } else if (instance.eGet(feature) == null) { // Must be single-valued! revision.set(feature, EStore.NO_INDEX, CDORevisionData.NIL); } } } }
protected void instanceToRevision() { InternalCDORevision revision = cdoRevision(); if (TRACER.isEnabled()) { TRACER.format( "Transfering instance to revision: {0} --> {1}", instance, revision); // $NON-NLS-1$ } // Handle containment instanceToRevisionContainment(); // Handle values for (EStructuralFeature feature : classInfo.getAllPersistentFeatures()) { instanceToRevisionFeature(feature); } revision.setUnchunked(); }
/** @since 3.0 */ protected void revisionToInstanceFeature(EStructuralFeature feature) { if (feature.isUnsettable() && !viewAndState.view.getStore().isSet(this, feature)) { // Clarify if this is sufficient for bidirectional references instance.eUnset(feature); return; } if (feature.isMany()) { if (TRACER.isEnabled()) { TRACER.format( "State of Object (" + this + "/" + instance + ") is : " + viewAndState.state); // $NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ } if (viewAndState.state == CDOState.CLEAN || viewAndState.state == CDOState.PROXY || viewAndState.state == CDOState.NEW || viewAndState.state == CDOState.DIRTY) { InternalCDORevision revision = cdoRevision(); int size = revision.size(feature); @SuppressWarnings("unchecked") InternalEList<Object> list = (InternalEList<Object>) instance.eGet(feature); clearEList(list); for (int i = 0; i < size; i++) { Object object = getValueFromRevision(feature, i); if (TRACER.isEnabled()) { TRACER.format( "Adding " + object + " to feature " + feature + "in instance " + instance); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ } // Disable notifications from value during the // invalidation in case of // eInverseAdd/eInverseRemove boolean eDeliver = false; if (object instanceof Notifier) { Notifier notifier = (Notifier) object; eDeliver = notifier.eDeliver(); if (eDeliver) { notifier.eSetDeliver(false); } } list.basicAdd(object, null); if (object instanceof Notifier && eDeliver) { Notifier notifier = (Notifier) object; notifier.eSetDeliver(eDeliver); } } } } else { // !feature.isMany() Object object = getValueFromRevision(feature, 0); if (feature instanceof EAttribute) { if (TRACER.isEnabled()) { TRACER.format( "Setting attribute value " + object + " to feature " + feature + " in instance " + instance); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ } // Just fake it for the store :( if (feature.isUnsettable() && object.equals(CDORevisionData.NIL)) { eSet(feature, null); } else { if (object != null) { eSet(feature, object); } else { // TODO Unset for features with non-null default values would not lead to null values. // Probably CDORevisionData.NIL has to be used, but that impacts all IStores. Deferred // ;-( eUnset(feature); } } } else { // EReferences if (TRACER.isEnabled()) { TRACER.format( "Adding object " + object + " to feature " + feature + " in instance " + instance); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ } // Disable notifications from value during the // invalidation in case of // eInverseAdd/eInverseRemove boolean eDeliver = false; if (object instanceof Notifier) { Notifier notifier = (Notifier) object; eDeliver = notifier.eDeliver(); if (eDeliver) { notifier.eSetDeliver(false); } } EObject oldContainerOfValue = null; boolean eDeliverForOldContainerOfValue = false; if (object instanceof InternalEObject) { InternalEObject eObject = (InternalEObject) object; oldContainerOfValue = eObject.eInternalContainer(); if (oldContainerOfValue != null) { eDeliverForOldContainerOfValue = oldContainerOfValue.eDeliver(); if (eDeliverForOldContainerOfValue) { oldContainerOfValue.eSetDeliver(false); } } } int featureID = instance.eClass().getFeatureID(feature); Class<? extends Object> baseClass = object == null ? null : object.getClass(); EStructuralFeature.Internal internalFeature = (EStructuralFeature.Internal) feature; EReference oppositeReference = internalFeature.getEOpposite(); if (oppositeReference != null) { if (object != null && object != instance.eGet(feature)) { // If you have a containment reference but the container is not set, but the object is // attached to a // resource // do not set the feature to null. Otherwise the object will be removed from the // container which is the // resource instead of the original container. As a result the object will be detached. // See // MapTest.testEObjectToEObjectValueContainedMap for more information if (object != instance.eContainer() || !oppositeReference.isContainment()) { instance.eInverseAdd((InternalEObject) object, featureID, baseClass, null); } if (!classInfo.hasPersistentOpposite(internalFeature)) { adjustTransientOppositeReference( instance, (InternalEObject) object, oppositeReference); } } } else { if (object != CDORevisionData.NIL) { EReference reference = (EReference) feature; if (reference.isContainment()) { if (object != null) { // Calling eSet it not the optimal approach, but currently there is no other way to // set the value here. // To avoid attaching already processed (clean) objects a check was introduced to // CDOResourceImpl.attached(EObject). // If we find a way to avoid the call of eSet and if we are able to only set the // feature value directly // this check can be removed from CDOResourceImpl. See also Bug 352204. instance.eSet(feature, object); } else { instance.eSet(feature, null); } } else { instance.eSet(feature, object); } } else { instance.eSet(feature, null); } } if (object instanceof Notifier && eDeliver) { Notifier notifier = (Notifier) object; notifier.eSetDeliver(eDeliver); } if (oldContainerOfValue != null && eDeliverForOldContainerOfValue) { oldContainerOfValue.eSetDeliver(eDeliverForOldContainerOfValue); } if (TRACER.isEnabled()) { TRACER.format( "Added object " + object + " to feature " + feature + " in instance " + instance); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ } } } }
protected void revisionToInstance() { synchronized (recursionCounter) { if (underConstruction) { // Return if revisionToInstance was called before to avoid doubled calls return; } underConstruction = true; InternalCDORevision revision = cdoRevision(); if (TRACER.isEnabled()) { TRACER.format( "Transfering revision to instance: {0} --> {1}", revision, instance); // $NON-NLS-1$ } boolean deliver = instance.eDeliver(); if (deliver) { instance.eSetDeliver(false); } Counter counter = recursionCounter.get(); if (counter == null) { counter = new Counter(); recursionCounter.set(counter); } InternalCDOResource resource = null; boolean bypassPermissionChecks = revision.bypassPermissionChecks(true); try { registerWrapper(this); counter.increment(); viewAndState.view.registerObject(this); revisionToInstanceResource(); revisionToInstanceContainer(); Resource eResource = instance.eResource(); if (eResource instanceof InternalCDOResource) { resource = (InternalCDOResource) eResource; resource.cdoInternalLoading(instance); } for (EStructuralFeature feature : classInfo.getAllPersistentFeatures()) { revisionToInstanceFeature(feature); } } catch (RuntimeException ex) { OM.LOG.error(ex); throw ex; } catch (Exception ex) { OM.LOG.error(ex); throw new CDOException(ex); } finally { try { revision.bypassPermissionChecks(bypassPermissionChecks); if (resource != null) { resource.cdoInternalLoadingDone(instance); } if (deliver) { instance.eSetDeliver(true); } } finally { if (counter.decrement() == 0) { recursionCounter.remove(); } unregisterWrapper(this); underConstruction = false; } } } }