|
Lines 20-36
Link Here
|
| 20 |
import org.eclipse.emf.cdo.common.model.EMFUtil; |
20 |
import org.eclipse.emf.cdo.common.model.EMFUtil; |
| 21 |
import org.eclipse.emf.cdo.common.protocol.CDOProtocolConstants; |
21 |
import org.eclipse.emf.cdo.common.protocol.CDOProtocolConstants; |
| 22 |
import org.eclipse.emf.cdo.common.revision.CDORevision; |
22 |
import org.eclipse.emf.cdo.common.revision.CDORevision; |
|
|
23 |
import org.eclipse.emf.cdo.common.revision.CDORevisionData; |
| 24 |
import org.eclipse.emf.cdo.common.util.CDOException; |
| 23 |
import org.eclipse.emf.cdo.eresource.CDOResource; |
25 |
import org.eclipse.emf.cdo.eresource.CDOResource; |
| 24 |
import org.eclipse.emf.cdo.spi.common.revision.InternalCDORevision; |
26 |
import org.eclipse.emf.cdo.spi.common.revision.InternalCDORevision; |
|
|
27 |
import org.eclipse.emf.cdo.util.CDOUtil; |
| 25 |
|
28 |
|
| 26 |
import org.eclipse.emf.internal.cdo.bundle.OM; |
29 |
import org.eclipse.emf.internal.cdo.bundle.OM; |
| 27 |
import org.eclipse.emf.internal.cdo.util.FSMUtil; |
30 |
import org.eclipse.emf.internal.cdo.util.FSMUtil; |
| 28 |
|
31 |
|
| 29 |
import org.eclipse.net4j.util.ImplementationError; |
|
|
| 30 |
import org.eclipse.net4j.util.ReflectUtil; |
32 |
import org.eclipse.net4j.util.ReflectUtil; |
|
|
33 |
import org.eclipse.net4j.util.WrappedException; |
| 31 |
import org.eclipse.net4j.util.om.trace.ContextTracer; |
34 |
import org.eclipse.net4j.util.om.trace.ContextTracer; |
| 32 |
|
35 |
|
| 33 |
import org.eclipse.emf.common.notify.Adapter; |
36 |
import org.eclipse.emf.common.notify.Adapter; |
|
|
37 |
import org.eclipse.emf.common.notify.impl.BasicNotifierImpl.EObservableAdapterList; |
| 38 |
import org.eclipse.emf.common.util.EList; |
| 34 |
import org.eclipse.emf.common.util.URI; |
39 |
import org.eclipse.emf.common.util.URI; |
| 35 |
import org.eclipse.emf.ecore.EAttribute; |
40 |
import org.eclipse.emf.ecore.EAttribute; |
| 36 |
import org.eclipse.emf.ecore.EClass; |
41 |
import org.eclipse.emf.ecore.EClass; |
|
Lines 41-46
Link Here
|
| 41 |
import org.eclipse.emf.ecore.InternalEObject; |
46 |
import org.eclipse.emf.ecore.InternalEObject; |
| 42 |
import org.eclipse.emf.ecore.resource.Resource; |
47 |
import org.eclipse.emf.ecore.resource.Resource; |
| 43 |
import org.eclipse.emf.ecore.util.InternalEList; |
48 |
import org.eclipse.emf.ecore.util.InternalEList; |
|
|
49 |
import org.eclipse.emf.spi.cdo.CDOElementProxy; |
| 44 |
import org.eclipse.emf.spi.cdo.InternalCDOObject; |
50 |
import org.eclipse.emf.spi.cdo.InternalCDOObject; |
| 45 |
import org.eclipse.emf.spi.cdo.InternalCDOView; |
51 |
import org.eclipse.emf.spi.cdo.InternalCDOView; |
| 46 |
|
52 |
|
|
Lines 59-78
Link Here
|
| 59 |
{ |
65 |
{ |
| 60 |
private static final ContextTracer TRACER = new ContextTracer(OM.DEBUG_OBJECT, CDOLegacyWrapper.class); |
66 |
private static final ContextTracer TRACER = new ContextTracer(OM.DEBUG_OBJECT, CDOLegacyWrapper.class); |
| 61 |
|
67 |
|
| 62 |
protected CDOState state; |
|
|
| 63 |
|
| 64 |
protected InternalCDORevision revision; |
| 65 |
|
| 66 |
/** |
| 67 |
* It could happen that while <i>revisionToInstance()</i> is executed externally the <i>internalPostLoad()</i> method |
| 68 |
* will be called. This happens for example if <i>internalPostInvalidate()</i> is called. The leads to another |
| 69 |
* <i>revisionToInstance()</i> call while the first call has not finished. This is certainly not so cool. That's why |
| 70 |
* <b>underConstruction</b> will flag that <i>revisionToInstance()</i> is still running and avoid the second call. |
| 71 |
* |
| 72 |
* @since 3.0 |
| 73 |
*/ |
| 74 |
private boolean underConstruction; |
| 75 |
|
| 76 |
/** |
68 |
/** |
| 77 |
* This local ThreadMap stores all pre-registered objects. This avoids a neverending loop when setting the container |
69 |
* This local ThreadMap stores all pre-registered objects. This avoids a neverending loop when setting the container |
| 78 |
* for the object. |
70 |
* for the object. |
|
Lines 95-104
Link Here
|
| 95 |
} |
87 |
} |
| 96 |
}; |
88 |
}; |
| 97 |
|
89 |
|
|
|
90 |
protected CDOState state; |
| 91 |
|
| 92 |
protected InternalCDORevision revision; |
| 93 |
|
| 94 |
/** |
| 95 |
* It could happen that while <i>revisionToInstance()</i> is executed externally the <i>internalPostLoad()</i> method |
| 96 |
* will be called. This happens for example if <i>internalPostInvalidate()</i> is called. The leads to another |
| 97 |
* <i>revisionToInstance()</i> call while the first call has not finished. This is certainly not so cool. That's why |
| 98 |
* <b>underConstruction</b> will flag that <i>revisionToInstance()</i> is still running and avoid the second call. |
| 99 |
* |
| 100 |
* @since 3.0 |
| 101 |
*/ |
| 102 |
private boolean underConstruction; |
| 103 |
|
| 98 |
public CDOLegacyWrapper(InternalEObject instance) |
104 |
public CDOLegacyWrapper(InternalEObject instance) |
| 99 |
{ |
105 |
{ |
| 100 |
this.instance = instance; |
106 |
this.instance = instance; |
| 101 |
state = CDOState.TRANSIENT; |
107 |
state = CDOState.TRANSIENT; |
|
|
108 |
|
| 109 |
instance.eAdapters().add((Adapter)this); |
| 110 |
attachAdapterListListener(); |
| 102 |
} |
111 |
} |
| 103 |
|
112 |
|
| 104 |
public CDOState cdoState() |
113 |
public CDOState cdoState() |
|
Lines 122-133
Link Here
|
| 122 |
{ |
131 |
{ |
| 123 |
if (TRACER.isEnabled()) |
132 |
if (TRACER.isEnabled()) |
| 124 |
{ |
133 |
{ |
| 125 |
TRACER.format("Setting state {0} for {1}", state, this); |
134 |
TRACER.format("Setting state {0} for {1}", state, this); //$NON-NLS-1$ |
| 126 |
} |
135 |
} |
| 127 |
|
136 |
|
| 128 |
CDOState oldState = this.state; |
137 |
CDOState oldState = this.state; |
| 129 |
this.state = state; |
138 |
this.state = state; |
| 130 |
adjustEProxy(); |
139 |
adjustEProxy(); |
|
|
140 |
|
| 131 |
if (view != null) |
141 |
if (view != null) |
| 132 |
{ |
142 |
{ |
| 133 |
view.handleObjectStateChanged(this, oldState, state); |
143 |
view.handleObjectStateChanged(this, oldState, state); |
|
Lines 143-149
Link Here
|
| 143 |
{ |
153 |
{ |
| 144 |
if (TRACER.isEnabled()) |
154 |
if (TRACER.isEnabled()) |
| 145 |
{ |
155 |
{ |
| 146 |
TRACER.format(("Setting revision: " + revision + "")); |
156 |
TRACER.trace(("Setting revision: " + revision)); //$NON-NLS-1$ |
| 147 |
} |
157 |
} |
| 148 |
|
158 |
|
| 149 |
this.revision = (InternalCDORevision)revision; |
159 |
this.revision = (InternalCDORevision)revision; |
|
Lines 153-183
Link Here
|
| 153 |
{ |
163 |
{ |
| 154 |
instanceToRevision(); |
164 |
instanceToRevision(); |
| 155 |
|
165 |
|
| 156 |
// TODO Avoid if no adapters in list (eBasicAdapters?) |
|
|
| 157 |
// TODO LEGACY Clarify how to intercept adapter addition in the legacy |
| 158 |
// instance |
| 159 |
for (Adapter adapter : eAdapters()) |
166 |
for (Adapter adapter : eAdapters()) |
| 160 |
{ |
167 |
{ |
| 161 |
view.subscribe(this, adapter); |
168 |
if (!(adapter instanceof CDOObjectWrapper)) |
|
|
169 |
{ |
| 170 |
view.handleAddAdapter(this, adapter); |
| 171 |
view.subscribe(this, adapter); |
| 172 |
} |
| 162 |
} |
173 |
} |
| 163 |
} |
174 |
} |
| 164 |
|
175 |
|
| 165 |
public void cdoInternalPostDetach(boolean remote) |
176 |
public void cdoInternalPostDetach(boolean remote) |
| 166 |
{ |
177 |
{ |
|
|
178 |
if (remote) |
| 179 |
{ |
| 180 |
// Do nothing?? |
| 181 |
return; |
| 182 |
} |
| 183 |
|
| 184 |
EClass eClass = revision.getEClass(); |
| 185 |
|
| 186 |
CDOStore store = view.getStore(); |
| 187 |
InternalEObject eContainer = store.getContainer(this); |
| 188 |
if (eContainer != null && eContainmentFeature().isResolveProxies()) |
| 189 |
{ |
| 190 |
adjustOppositeReference(this, eContainer, eContainmentFeature()); |
| 191 |
} |
| 192 |
|
| 193 |
// This loop adjusts the opposite wrapper objects to support dangling references. See Bugzilla_251263_Test |
| 194 |
for (EStructuralFeature feature : CDOModelUtil.getAllPersistentFeatures(eClass)) |
| 195 |
{ |
| 196 |
EReference oppositeReference = ((EStructuralFeature.Internal)feature).getEOpposite(); |
| 197 |
if (oppositeReference != null) |
| 198 |
{ |
| 199 |
if (feature.isMany()) |
| 200 |
{ |
| 201 |
int size = revision.size(feature); |
| 202 |
for (int i = 0; i < size; i++) |
| 203 |
{ |
| 204 |
EObject object = (EObject)getValueFromRevision(feature, i); |
| 205 |
CDOObjectWrapper wrapper = (CDOObjectWrapper)CDOUtil.getCDOObject(object); |
| 206 |
setOppositeReference(wrapper, oppositeReference); |
| 207 |
} |
| 208 |
} |
| 209 |
else |
| 210 |
{ |
| 211 |
EObject oppositeObject = (EObject)instance.eGet(feature); |
| 212 |
if (oppositeObject != null) |
| 213 |
{ |
| 214 |
CDOObjectWrapper wrapper = (CDOObjectWrapper)CDOUtil.getCDOObject(oppositeObject); |
| 215 |
setOppositeReference(wrapper, oppositeReference); |
| 216 |
} |
| 217 |
} |
| 218 |
} |
| 219 |
} |
| 220 |
} |
| 221 |
|
| 222 |
private void setOppositeReference(CDOObjectWrapper wrapper, EReference oppositeReference) |
| 223 |
{ |
| 224 |
if (wrapper != null) |
| 225 |
{ |
| 226 |
InternalCDOView view = wrapper.cdoView(); |
| 227 |
if (view != null) |
| 228 |
{ |
| 229 |
CDOStore store = view.getStore(); |
| 230 |
if (store != null) |
| 231 |
{ |
| 232 |
store.set(wrapper, oppositeReference, 0, this); |
| 233 |
} |
| 234 |
} |
| 235 |
} |
| 236 |
} |
| 237 |
|
| 238 |
/** |
| 239 |
* @since 3.0 |
| 240 |
*/ |
| 241 |
public void cdoInternalPostRollback() |
| 242 |
{ |
| 243 |
InternalCDORevision revision = cdoView().getRevision(cdoID(), true); |
| 244 |
cdoInternalSetRevision(revision); |
| 245 |
revisionToInstance(); |
| 246 |
state = CDOState.CLEAN; |
| 167 |
} |
247 |
} |
| 168 |
|
248 |
|
|
|
249 |
/** |
| 250 |
* CDO persists the isUnset state of an eObject in the database. The indicator for this is that the feature is null in |
| 251 |
* the revision (see CDOStore.isSet()). When committing a legacy object all values in the instance for native |
| 252 |
* attributes are set with the java default values. So, these values will be stored in the revision and CDO cannot |
| 253 |
* distinguish whether the feature is set or not. This method must ensure that the value will be set to null if the |
| 254 |
* feature is not set. |
| 255 |
*/ |
| 169 |
public void cdoInternalPreCommit() |
256 |
public void cdoInternalPreCommit() |
| 170 |
{ |
257 |
{ |
|
|
258 |
// We have to set this here because the CDOLegacyAdapter will not be notified when the instance is the target of a |
| 259 |
// single-directional containment reference. |
| 260 |
// If the container is not an legacy Object the system will get no information |
| 261 |
instanceToRevisionContainment(); |
| 262 |
|
| 263 |
EClass eClass = revision.getEClass(); |
| 264 |
for (EStructuralFeature feature : CDOModelUtil.getAllPersistentFeatures(eClass)) |
| 265 |
{ |
| 266 |
if (feature.isUnsettable()) |
| 267 |
{ |
| 268 |
if (!instance.eIsSet(feature)) |
| 269 |
{ |
| 270 |
if (feature.isMany()) |
| 271 |
{ |
| 272 |
@SuppressWarnings("unchecked") |
| 273 |
InternalEList<Object> list = (InternalEList<Object>)instance.eGet(feature); |
| 274 |
clearList(feature, list); |
| 275 |
} |
| 276 |
else |
| 277 |
{ |
| 278 |
revision.set(feature, EStore.NO_INDEX, null); |
| 279 |
} |
| 280 |
} |
| 281 |
else if (instance.eGet(feature) == null) |
| 282 |
{ |
| 283 |
// Must be single-valued! |
| 284 |
revision.set(feature, EStore.NO_INDEX, CDORevisionData.NIL); |
| 285 |
} |
| 286 |
} |
| 287 |
} |
| 171 |
} |
288 |
} |
| 172 |
|
289 |
|
| 173 |
public void cdoInternalPreLoad() |
290 |
public void cdoInternalPreLoad() |
| 174 |
{ |
291 |
{ |
|
|
292 |
// Do nothing |
| 175 |
} |
293 |
} |
| 176 |
|
294 |
|
| 177 |
public void cdoInternalPostLoad() |
295 |
public void cdoInternalPostLoad() |
| 178 |
{ |
296 |
{ |
| 179 |
// TODO Consider not remembering the revisin after copying it to the |
297 |
// TODO Consider not remembering the revision after copying it to the instance (spare 1/2 of the space) |
| 180 |
// instance (spare 1/2 of the space) |
|
|
| 181 |
revisionToInstance(); |
298 |
revisionToInstance(); |
| 182 |
} |
299 |
} |
| 183 |
|
300 |
|
|
Lines 191-197
Link Here
|
| 191 |
|
308 |
|
| 192 |
public void cdoInternalCleanup() |
309 |
public void cdoInternalCleanup() |
| 193 |
{ |
310 |
{ |
| 194 |
// clean(); |
311 |
// Do nothing |
| 195 |
} |
312 |
} |
| 196 |
|
313 |
|
| 197 |
@Override |
314 |
@Override |
|
Lines 214-227
Link Here
|
| 214 |
@Override |
331 |
@Override |
| 215 |
public String toString() |
332 |
public String toString() |
| 216 |
{ |
333 |
{ |
| 217 |
return "CDOLegacyWrapper[" + id + "]"; |
334 |
return "CDOLegacyWrapper[" + id + ", " + instance.getClass().getName() + "]"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ |
|
|
335 |
} |
| 336 |
|
| 337 |
/** |
| 338 |
* @since 3.0 |
| 339 |
*/ |
| 340 |
protected void attachAdapterListListener() |
| 341 |
{ |
| 342 |
((EObservableAdapterList)instance.eAdapters()).addListener(new AdapterListListener()); |
| 218 |
} |
343 |
} |
| 219 |
|
344 |
|
| 220 |
protected void instanceToRevision() |
345 |
protected void instanceToRevision() |
| 221 |
{ |
346 |
{ |
| 222 |
if (TRACER.isEnabled()) |
347 |
if (TRACER.isEnabled()) |
| 223 |
{ |
348 |
{ |
| 224 |
TRACER.format("Transfering instance to revision: {0} --> {1}", instance, revision); |
349 |
TRACER.format("Transfering instance to revision: {0} --> {1}", instance, revision); //$NON-NLS-1$ |
| 225 |
} |
350 |
} |
| 226 |
|
351 |
|
| 227 |
// Handle containment |
352 |
// Handle containment |
|
Lines 250-256
Link Here
|
| 250 |
else |
375 |
else |
| 251 |
{ |
376 |
{ |
| 252 |
CDOObject cdoContainer = FSMUtil.adapt(eContainer, view); |
377 |
CDOObject cdoContainer = FSMUtil.adapt(eContainer, view); |
| 253 |
revision.setContainerID(cdoContainer.cdoID()); |
378 |
revision.setContainerID(cdoContainer); |
| 254 |
revision.setContainingFeatureID(getInstanceContainerFeatureID(instance)); |
379 |
revision.setContainingFeatureID(getInstanceContainerFeatureID(instance)); |
| 255 |
} |
380 |
} |
| 256 |
} |
381 |
} |
|
Lines 265-271
Link Here
|
| 265 |
{ |
390 |
{ |
| 266 |
if (underConstruction) |
391 |
if (underConstruction) |
| 267 |
{ |
392 |
{ |
| 268 |
// return if revisionToInstance was called before to avoid doubled calls |
393 |
// Return if revisionToInstance was called before to avoid doubled calls |
| 269 |
return; |
394 |
return; |
| 270 |
} |
395 |
} |
| 271 |
|
396 |
|
|
Lines 273-279
Link Here
|
| 273 |
|
398 |
|
| 274 |
if (TRACER.isEnabled()) |
399 |
if (TRACER.isEnabled()) |
| 275 |
{ |
400 |
{ |
| 276 |
TRACER.format("Transfering revision to instance: {0} --> {1}", revision, instance); |
401 |
TRACER.format("Transfering revision to instance: {0} --> {1}", revision, instance); //$NON-NLS-1$ |
| 277 |
} |
402 |
} |
| 278 |
|
403 |
|
| 279 |
boolean deliver = instance.eDeliver(); |
404 |
boolean deliver = instance.eDeliver(); |
|
Lines 287-293
Link Here
|
| 287 |
{ |
412 |
{ |
| 288 |
registerWrapper(this); |
413 |
registerWrapper(this); |
| 289 |
counter.increment(); |
414 |
counter.increment(); |
| 290 |
|
|
|
| 291 |
revisionToInstanceContainment(); |
415 |
revisionToInstanceContainment(); |
| 292 |
|
416 |
|
| 293 |
for (EStructuralFeature feature : CDOModelUtil.getAllPersistentFeatures(revision.getEClass())) |
417 |
for (EStructuralFeature feature : CDOModelUtil.getAllPersistentFeatures(revision.getEClass())) |
|
Lines 300-305
Link Here
|
| 300 |
OM.LOG.error(ex); |
424 |
OM.LOG.error(ex); |
| 301 |
throw ex; |
425 |
throw ex; |
| 302 |
} |
426 |
} |
|
|
427 |
catch (Exception ex) |
| 428 |
{ |
| 429 |
OM.LOG.error(ex); |
| 430 |
throw new CDOException(ex); |
| 431 |
} |
| 303 |
finally |
432 |
finally |
| 304 |
{ |
433 |
{ |
| 305 |
if (deliver) |
434 |
if (deliver) |
|
Lines 329-342
Link Here
|
| 329 |
*/ |
458 |
*/ |
| 330 |
protected void revisionToInstanceFeature(EStructuralFeature feature) |
459 |
protected void revisionToInstanceFeature(EStructuralFeature feature) |
| 331 |
{ |
460 |
{ |
|
|
461 |
if (feature.isUnsettable() && !view.getStore().isSet(this, feature)) |
| 462 |
{ |
| 463 |
// Clarify if this is sufficient for bidirectional references |
| 464 |
instance.eUnset(feature); |
| 465 |
return; |
| 466 |
} |
| 467 |
|
| 332 |
if (feature.isMany()) |
468 |
if (feature.isMany()) |
| 333 |
{ |
469 |
{ |
| 334 |
if (TRACER.isEnabled()) |
470 |
if (TRACER.isEnabled()) |
| 335 |
{ |
471 |
{ |
| 336 |
TRACER.format("State of Object is : " + state); |
472 |
TRACER.format("State of Object (" + this + "/" + instance + ") is : " + state); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ |
| 337 |
} |
473 |
} |
| 338 |
|
474 |
|
| 339 |
if (state == CDOState.CLEAN || state == CDOState.PROXY) |
475 |
if (state == CDOState.CLEAN || state == CDOState.PROXY || state == CDOState.NEW || state == CDOState.DIRTY) |
| 340 |
{ |
476 |
{ |
| 341 |
int size = revision.size(feature); |
477 |
int size = revision.size(feature); |
| 342 |
|
478 |
|
|
Lines 350-356
Link Here
|
| 350 |
|
486 |
|
| 351 |
if (TRACER.isEnabled()) |
487 |
if (TRACER.isEnabled()) |
| 352 |
{ |
488 |
{ |
| 353 |
TRACER.format("Adding " + object + " to feature " + feature + "in instance " + instance); |
489 |
TRACER.format("Adding " + object + " to feature " + feature + "in instance " + instance); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ |
| 354 |
} |
490 |
} |
| 355 |
|
491 |
|
| 356 |
list.basicAdd(object, null); |
492 |
list.basicAdd(object, null); |
|
Lines 365-391
Link Here
|
| 365 |
{ |
501 |
{ |
| 366 |
if (TRACER.isEnabled()) |
502 |
if (TRACER.isEnabled()) |
| 367 |
{ |
503 |
{ |
| 368 |
TRACER.format(("Setting attribute value " + object + " to feature " + feature + " in instance " + instance)); |
504 |
TRACER.format(("Setting attribute value " + object + " to feature " + feature + " in instance " + instance)); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ |
| 369 |
} |
505 |
} |
| 370 |
|
506 |
|
| 371 |
eSet(feature, object); |
507 |
// Just fake it for the store :( |
|
|
508 |
if (feature.isUnsettable() && object.equals(CDORevisionData.NIL)) |
| 509 |
{ |
| 510 |
eSet(feature, null); |
| 511 |
} |
| 512 |
else |
| 513 |
{ |
| 514 |
eSet(feature, object); |
| 515 |
} |
| 372 |
} |
516 |
} |
| 373 |
else |
517 |
else |
| 374 |
{ |
518 |
{ |
| 375 |
// EReferences |
519 |
// EReferences |
| 376 |
if (TRACER.isEnabled()) |
520 |
if (TRACER.isEnabled()) |
| 377 |
{ |
521 |
{ |
| 378 |
TRACER.format(("Adding object " + object + " to feature " + feature + " in instance " + instance)); |
522 |
TRACER.format(("Adding object " + object + " to feature " + feature + " in instance " + instance)); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ |
| 379 |
} |
523 |
} |
| 380 |
|
524 |
|
| 381 |
int featureID = instance.eClass().getFeatureID(feature); |
525 |
int featureID = instance.eClass().getFeatureID(feature); |
| 382 |
Class<? extends Object> baseClass = object == null ? null : object.getClass(); |
526 |
Class<? extends Object> baseClass = object == null ? null : object.getClass(); |
| 383 |
EStructuralFeature.Internal internalFeature = (EStructuralFeature.Internal)feature; |
527 |
EStructuralFeature.Internal internalFeature = (EStructuralFeature.Internal)feature; |
| 384 |
EReference oppositeReference = cdoID().isTemporary() ? null : internalFeature.getEOpposite(); |
528 |
EReference oppositeReference = internalFeature.getEOpposite(); |
| 385 |
|
529 |
|
| 386 |
if (oppositeReference != null) |
530 |
if (oppositeReference != null) |
| 387 |
{ |
531 |
{ |
| 388 |
instance.eInverseAdd((InternalEObject)object, featureID, baseClass, null); |
532 |
// If you have a containment reference but the container is not set, but the object is attached to a resource |
|
|
533 |
// do not set the feature to null. Otherwise the object will be removed from the container which is the |
| 534 |
// resource instead of the original container. As a result the object will be detached. See |
| 535 |
// MapTest.testEObjectToEObjectValueContainedMap for more information |
| 536 |
if (object != null) |
| 537 |
{ |
| 538 |
instance.eInverseAdd((InternalEObject)object, featureID, baseClass, null); |
| 539 |
} |
| 389 |
|
540 |
|
| 390 |
if (object != null && !EMFUtil.isPersistent(oppositeReference)) |
541 |
if (object != null && !EMFUtil.isPersistent(oppositeReference)) |
| 391 |
{ |
542 |
{ |
|
Lines 394-406
Link Here
|
| 394 |
} |
545 |
} |
| 395 |
else |
546 |
else |
| 396 |
{ |
547 |
{ |
| 397 |
instance.eSet(feature, object); |
548 |
if (object != CDORevisionData.NIL) |
|
|
549 |
{ |
| 550 |
instance.eSet(feature, object); |
| 551 |
} |
| 552 |
else |
| 553 |
{ |
| 554 |
instance.eSet(feature, null); |
| 555 |
} |
| 398 |
} |
556 |
} |
| 399 |
|
557 |
|
| 400 |
// Adjust opposite for transient opposite features |
|
|
| 401 |
if (TRACER.isEnabled()) |
558 |
if (TRACER.isEnabled()) |
| 402 |
{ |
559 |
{ |
| 403 |
TRACER.format(("Added object " + object + " to feature " + feature + " in instance " + instance)); |
560 |
TRACER.format(("Added object " + object + " to feature " + feature + " in instance " + instance)); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ |
| 404 |
} |
561 |
} |
| 405 |
} |
562 |
} |
| 406 |
} |
563 |
} |
|
Lines 408-415
Link Here
|
| 408 |
|
565 |
|
| 409 |
private void adjustOppositeReference(InternalEObject instance, InternalEObject object, EReference oppositeReference) |
566 |
private void adjustOppositeReference(InternalEObject instance, InternalEObject object, EReference oppositeReference) |
| 410 |
{ |
567 |
{ |
| 411 |
boolean deliver = object.eDeliver(); // Disable notifications |
568 |
boolean wasDeliver = object.eDeliver(); // Disable notifications |
| 412 |
if (deliver) |
569 |
if (wasDeliver) |
| 413 |
{ |
570 |
{ |
| 414 |
object.eSetDeliver(false); |
571 |
object.eSetDeliver(false); |
| 415 |
} |
572 |
} |
|
Lines 434-440
Link Here
|
| 434 |
} |
591 |
} |
| 435 |
finally |
592 |
finally |
| 436 |
{ |
593 |
{ |
| 437 |
if (deliver) |
594 |
if (wasDeliver) |
| 438 |
{ |
595 |
{ |
| 439 |
object.eSetDeliver(true); |
596 |
object.eSetDeliver(true); |
| 440 |
} |
597 |
} |
|
Lines 449-457
Link Here
|
| 449 |
|
606 |
|
| 450 |
// TODO Clarify obj.getClass()/baseclass |
607 |
// TODO Clarify obj.getClass()/baseclass |
| 451 |
((InternalEList<?>)list).basicRemove(obj, null); |
608 |
((InternalEList<?>)list).basicRemove(obj, null); |
| 452 |
|
|
|
| 453 |
// TODO Martin: baseicRemove seems to be better than eInverseremove |
| 454 |
// instance.eInverseRemove(obj, featureID, obj.getClass(), null); |
| 455 |
} |
609 |
} |
| 456 |
} |
610 |
} |
| 457 |
|
611 |
|
|
Lines 460-466
Link Here
|
| 460 |
* store or the internal pre-registration Map. |
614 |
* store or the internal pre-registration Map. |
| 461 |
* |
615 |
* |
| 462 |
* @param feature |
616 |
* @param feature |
| 463 |
* the feature to retireive the value from |
617 |
* the feature to retrieve the value from |
| 464 |
* @param index |
618 |
* @param index |
| 465 |
* the given index of the object in the feature |
619 |
* the given index of the object in the feature |
| 466 |
* @return the value from the feature at the given index |
620 |
* @return the value from the feature at the given index |
|
Lines 473-478
Link Here
|
| 473 |
return null; |
627 |
return null; |
| 474 |
} |
628 |
} |
| 475 |
|
629 |
|
|
|
630 |
if (object instanceof CDOElementProxy) |
| 631 |
{ |
| 632 |
// Resolve proxy |
| 633 |
object = ((CDOElementProxy)object).resolve(view.getSession(), revision, feature, index); |
| 634 |
} |
| 635 |
|
| 476 |
if (object instanceof CDOLegacyWrapper) |
636 |
if (object instanceof CDOLegacyWrapper) |
| 477 |
{ |
637 |
{ |
| 478 |
return ((CDOLegacyWrapper)object).cdoInternalInstance(); |
638 |
return ((CDOLegacyWrapper)object).cdoInternalInstance(); |
|
Lines 497-503
Link Here
|
| 497 |
return ((CDOLegacyWrapper)object).cdoInternalInstance(); |
657 |
return ((CDOLegacyWrapper)object).cdoInternalInstance(); |
| 498 |
} |
658 |
} |
| 499 |
|
659 |
|
| 500 |
object = view.getObject(id); |
660 |
if (id.isExternal()) |
|
|
661 |
{ |
| 662 |
object = view.getResourceSet().getEObject(URI.createURI(id.toURIFragment()), true); |
| 663 |
} |
| 664 |
else |
| 665 |
{ |
| 666 |
object = view.getObject(id); |
| 667 |
} |
| 668 |
|
| 501 |
if (object instanceof CDOObjectWrapper) |
669 |
if (object instanceof CDOObjectWrapper) |
| 502 |
{ |
670 |
{ |
| 503 |
return ((CDOObjectWrapper)object).cdoInternalInstance(); |
671 |
return ((CDOObjectWrapper)object).cdoInternalInstance(); |
|
Lines 537-543
Link Here
|
| 537 |
|
705 |
|
| 538 |
protected void setInstanceContainer(InternalEObject container, int containerFeatureID) |
706 |
protected void setInstanceContainer(InternalEObject container, int containerFeatureID) |
| 539 |
{ |
707 |
{ |
| 540 |
// TODO Change to direct call of eBasicSetContainer |
|
|
| 541 |
Method method = ReflectUtil.getMethod(instance.getClass(), "eBasicSetContainer", InternalEObject.class, int.class); //$NON-NLS-1$ |
708 |
Method method = ReflectUtil.getMethod(instance.getClass(), "eBasicSetContainer", InternalEObject.class, int.class); //$NON-NLS-1$ |
| 542 |
ReflectUtil.invokeMethod(method, instance, container, containerFeatureID); |
709 |
ReflectUtil.invokeMethod(method, instance, container, containerFeatureID); |
| 543 |
} |
710 |
} |
|
Lines 563-569
Link Here
|
| 563 |
|
730 |
|
| 564 |
if (TRACER.isEnabled()) |
731 |
if (TRACER.isEnabled()) |
| 565 |
{ |
732 |
{ |
| 566 |
TRACER.format("getting Object (" + potentialID + ") from localThread instead of the view"); |
733 |
TRACER.format("Getting Object (" + potentialID + ") from localThread instead of the view"); //$NON-NLS-1$ //$NON-NLS-2$ |
| 567 |
} |
734 |
} |
| 568 |
} |
735 |
} |
| 569 |
else |
736 |
else |
|
Lines 576-581
Link Here
|
| 576 |
return null; |
743 |
return null; |
| 577 |
} |
744 |
} |
| 578 |
|
745 |
|
|
|
746 |
if (id.isExternal()) |
| 747 |
{ |
| 748 |
URI uri = URI.createURI(id.toURIFragment()); |
| 749 |
InternalEObject eObject = (InternalEObject)view.getResourceSet().getEObject(uri, true); |
| 750 |
return eObject; |
| 751 |
} |
| 752 |
|
| 579 |
boolean loadOnDemand = feature == null; |
753 |
boolean loadOnDemand = feature == null; |
| 580 |
potentialID = view.getObject(id, loadOnDemand); |
754 |
potentialID = view.getObject(id, loadOnDemand); |
| 581 |
if (potentialID == null && !loadOnDemand) |
755 |
if (potentialID == null && !loadOnDemand) |
|
Lines 727-733
Link Here
|
| 727 |
URI uri = URI.createURI(CDOProtocolConstants.PROTOCOL_NAME + ":proxy#" + id); //$NON-NLS-1$ |
901 |
URI uri = URI.createURI(CDOProtocolConstants.PROTOCOL_NAME + ":proxy#" + id); //$NON-NLS-1$ |
| 728 |
if (TRACER.isEnabled()) |
902 |
if (TRACER.isEnabled()) |
| 729 |
{ |
903 |
{ |
| 730 |
TRACER.format("Setting proxyURI {0} for {1}", uri, instance); |
904 |
TRACER.format("Setting proxyURI {0} for {1}", uri, instance); //$NON-NLS-1$ |
| 731 |
} |
905 |
} |
| 732 |
|
906 |
|
| 733 |
instance.eSetProxyURI(uri); |
907 |
instance.eSetProxyURI(uri); |
|
Lines 739-745
Link Here
|
| 739 |
{ |
913 |
{ |
| 740 |
if (TRACER.isEnabled()) |
914 |
if (TRACER.isEnabled()) |
| 741 |
{ |
915 |
{ |
| 742 |
TRACER.format("Unsetting proxyURI for {0}", instance); |
916 |
TRACER.format("Unsetting proxyURI for {0}", instance); //$NON-NLS-1$ |
| 743 |
} |
917 |
} |
| 744 |
|
918 |
|
| 745 |
instance.eSetProxyURI(null); |
919 |
instance.eSetProxyURI(null); |
|
Lines 747-752
Link Here
|
| 747 |
} |
921 |
} |
| 748 |
} |
922 |
} |
| 749 |
|
923 |
|
|
|
924 |
@Override |
| 925 |
public synchronized EList<Adapter> eAdapters() |
| 926 |
{ |
| 927 |
EList<Adapter> adapters = instance.eAdapters(); |
| 928 |
for (Adapter adapter : adapters) |
| 929 |
{ |
| 930 |
if (!FSMUtil.isTransient(this) && !(adapter instanceof CDOLegacyWrapper)) |
| 931 |
{ |
| 932 |
cdoView().handleAddAdapter(this, adapter); |
| 933 |
} |
| 934 |
} |
| 935 |
|
| 936 |
return adapters; |
| 937 |
} |
| 938 |
|
| 750 |
public static boolean isLegacyProxy(Object object) |
939 |
public static boolean isLegacyProxy(Object object) |
| 751 |
{ |
940 |
{ |
| 752 |
return object instanceof LegacyProxy; |
941 |
return object instanceof LegacyProxy; |
|
Lines 766-795
Link Here
|
| 766 |
} |
955 |
} |
| 767 |
catch (IllegalAccessException ex) |
956 |
catch (IllegalAccessException ex) |
| 768 |
{ |
957 |
{ |
| 769 |
throw new ImplementationError(ex); |
958 |
throw WrappedException.wrap(ex); |
| 770 |
} |
959 |
} |
| 771 |
} |
960 |
} |
| 772 |
|
961 |
|
| 773 |
private static CDOLegacyWrapper getRegisteredWrapper(CDOID id) |
962 |
/** |
|
|
963 |
* @since 3.0 |
| 964 |
*/ |
| 965 |
protected static CDOLegacyWrapper getRegisteredWrapper(CDOID id) |
| 774 |
{ |
966 |
{ |
| 775 |
return wrapperRegistry.get().get(id); |
967 |
return wrapperRegistry.get().get(id); |
| 776 |
} |
968 |
} |
| 777 |
|
969 |
|
| 778 |
/** |
970 |
/** |
| 779 |
* adds an object to the pre-registered objects list which hold all created objects even if they are not registered in |
971 |
* Adds an object to the pre-registered objects list which hold all created objects even if they are not registered in |
| 780 |
* the view |
972 |
* the view |
|
|
973 |
* |
| 974 |
* @since 3.0 |
| 781 |
*/ |
975 |
*/ |
| 782 |
private static void registerWrapper(CDOLegacyWrapper wrapper) |
976 |
protected static void registerWrapper(CDOLegacyWrapper wrapper) |
| 783 |
{ |
977 |
{ |
| 784 |
wrapperRegistry.get().put(wrapper.cdoID(), wrapper); |
978 |
wrapperRegistry.get().put(wrapper.cdoID(), wrapper); |
| 785 |
} |
979 |
} |
| 786 |
|
980 |
|
| 787 |
private static void unregisterWrapper(CDOLegacyWrapper wrapper) |
981 |
/** |
|
|
982 |
* @since 3.0 |
| 983 |
*/ |
| 984 |
protected static void unregisterWrapper(CDOLegacyWrapper wrapper) |
| 788 |
{ |
985 |
{ |
| 789 |
wrapperRegistry.get().remove(wrapper.cdoID()); |
986 |
wrapperRegistry.get().remove(wrapper.cdoID()); |
| 790 |
} |
987 |
} |
| 791 |
|
988 |
|
| 792 |
/** |
989 |
/** |
|
|
990 |
* @since 3.0 |
| 991 |
*/ |
| 992 |
protected static boolean isRegisteredWrapper(CDOLegacyWrapper wrapper) |
| 993 |
{ |
| 994 |
return wrapperRegistry.get().containsKey(wrapper.cdoID()); |
| 995 |
} |
| 996 |
|
| 997 |
private static void adjustOppositeReference(InternalCDOObject instance, InternalEObject object, EReference feature) |
| 998 |
{ |
| 999 |
if (object != null) |
| 1000 |
{ |
| 1001 |
InternalCDOObject cdoObject = (InternalCDOObject)CDOUtil.getCDOObject(object); |
| 1002 |
if (cdoObject != null && !FSMUtil.isTransient(cdoObject)) |
| 1003 |
{ |
| 1004 |
EStore eStore = cdoObject.eStore(); |
| 1005 |
if (feature.isMany()) |
| 1006 |
{ |
| 1007 |
int index = eStore.indexOf(cdoObject, feature, instance.cdoID()); |
| 1008 |
if (index != EStore.NO_INDEX) |
| 1009 |
{ |
| 1010 |
eStore.set(cdoObject, feature, index, instance); |
| 1011 |
} |
| 1012 |
} |
| 1013 |
else |
| 1014 |
{ |
| 1015 |
eStore.set(cdoObject, feature, 0, instance); |
| 1016 |
} |
| 1017 |
} |
| 1018 |
else |
| 1019 |
{ |
| 1020 |
if (feature.isResolveProxies()) |
| 1021 |
{ |
| 1022 |
// We should not trigger events. But we have no choice :-(. |
| 1023 |
if (feature.isMany()) |
| 1024 |
{ |
| 1025 |
@SuppressWarnings("unchecked") |
| 1026 |
InternalEList<Object> list = (InternalEList<Object>)object.eGet(feature); |
| 1027 |
int index = list.indexOf(instance); |
| 1028 |
if (index != EStore.NO_INDEX) |
| 1029 |
{ |
| 1030 |
list.set(index, instance); |
| 1031 |
} |
| 1032 |
} |
| 1033 |
else |
| 1034 |
{ |
| 1035 |
object.eSet(feature, instance); |
| 1036 |
} |
| 1037 |
} |
| 1038 |
} |
| 1039 |
} |
| 1040 |
} |
| 1041 |
|
| 1042 |
/** |
| 793 |
* @author Eike Stepper |
1043 |
* @author Eike Stepper |
| 794 |
*/ |
1044 |
*/ |
| 795 |
private static interface LegacyProxy |
1045 |
private static interface LegacyProxy |
|
Lines 802-812
Link Here
|
| 802 |
*/ |
1052 |
*/ |
| 803 |
private static final class LegacyProxyInvocationHandler implements InvocationHandler, LegacyProxy |
1053 |
private static final class LegacyProxyInvocationHandler implements InvocationHandler, LegacyProxy |
| 804 |
{ |
1054 |
{ |
| 805 |
private static final Method getIDMethod = ReflectUtil.getMethod(LegacyProxy.class, "getID"); |
1055 |
private static final Method getIDMethod = ReflectUtil.getMethod(LegacyProxy.class, "getID"); //$NON-NLS-1$ |
| 806 |
|
1056 |
|
| 807 |
private static final Method eIsProxyMethod = ReflectUtil.getMethod(EObject.class, "eIsProxy"); |
1057 |
private static final Method eIsProxyMethod = ReflectUtil.getMethod(EObject.class, "eIsProxy"); //$NON-NLS-1$ |
| 808 |
|
1058 |
|
| 809 |
private static final Method eProxyURIMethod = ReflectUtil.getMethod(InternalEObject.class, "eProxyURI"); |
1059 |
private static final Method eProxyURIMethod = ReflectUtil.getMethod(InternalEObject.class, "eProxyURI"); //$NON-NLS-1$ |
| 810 |
|
1060 |
|
| 811 |
private CDOLegacyWrapper wrapper; |
1061 |
private CDOLegacyWrapper wrapper; |
| 812 |
|
1062 |
|
|
Lines 837-854
Link Here
|
| 837 |
|
1087 |
|
| 838 |
if (method.equals(eProxyURIMethod)) |
1088 |
if (method.equals(eProxyURIMethod)) |
| 839 |
{ |
1089 |
{ |
| 840 |
// Use the resource of the container because it's guaranteed to |
1090 |
// Use container's resource because it's guaranteed to be in the same CDOView as the resource of the target! |
| 841 |
// be in the same CDOView as the resource |
|
|
| 842 |
// of the target! |
| 843 |
Resource resource = wrapper.eResource(); |
1091 |
Resource resource = wrapper.eResource(); |
| 844 |
|
1092 |
|
| 845 |
// TODO Consider using a "fake" Resource implementation. See |
1093 |
// TODO Consider using a "fake" Resource implementation. See Resource.getEObject(...) |
| 846 |
// Resource.getEObject(...) |
|
|
| 847 |
return resource.getURI().appendFragment(id.toURIFragment()); |
1094 |
return resource.getURI().appendFragment(id.toURIFragment()); |
| 848 |
} |
1095 |
} |
| 849 |
|
1096 |
|
| 850 |
// A client must have invoked the proxy while being told not to do |
1097 |
// A client must have invoked the proxy while being told not to do so! |
| 851 |
// so! |
|
|
| 852 |
throw new UnsupportedOperationException(method.getName()); |
1098 |
throw new UnsupportedOperationException(method.getName()); |
| 853 |
} |
1099 |
} |
| 854 |
} |
1100 |
} |