Some Eclipse Foundation services are deprecated, or will be soon. Please ensure you've read this important communication.

Bug 339908

Summary: Can not get long id from external ID types.
Product: [Modeling] EMF Reporter: Stephane fournier <stephane.fournier>
Component: cdo.coreAssignee: Eike Stepper <stepper>
Status: CLOSED WORKSFORME QA Contact: Eike Stepper <stepper>
Severity: normal    
Priority: P3 CC: stefan.schalomon, stefan, stepper
Version: 4.2   
Target Milestone: ---   
Hardware: PC   
OS: Windows XP   
Whiteboard:
Attachments:
Description Flags
Screenshot none

Description Stephane fournier CLA 2011-03-14 11:23:28 EDT
Build Identifier: CDO 4.0.0 M5

I use a model that relies on UUID (java.util.UUID.randomUUID()) as technical ID serialized by EMF, when I persist such a model in a CDO repository, my model validation fails with exceptions see below.

It only works with such ID starting with alpha characters. If it starts with numerical characters, it leads to the exceptions.

[ERROR] Can not get long id from external ID types
java.lang.IllegalArgumentException: Can not get long id from external ID types
	at org.eclipse.emf.cdo.common.id.CDOIDUtil.getLong(CDOIDUtil.java:85)
	at org.eclipse.emf.cdo.server.internal.db.mapping.horizontal.DelegatingObjectTypeMapper.getObjectType(DelegatingObjectTypeMapper.java:55)
	at org.eclipse.emf.cdo.server.internal.db.mapping.horizontal.AbstractHorizontalMappingStrategy.readObjectType(AbstractHorizontalMappingStrategy.java:73)
	at org.eclipse.emf.cdo.server.internal.db.DBStoreAccessor.readObjectType(DBStoreAccessor.java:170)
	at org.eclipse.emf.cdo.server.internal.db.DBStoreAccessor.getObjectType(DBStoreAccessor.java:187)
	at org.eclipse.emf.cdo.server.internal.db.DBStoreAccessor.readRevision(DBStoreAccessor.java:207)
	at org.eclipse.emf.cdo.internal.server.Repository.loadRevisions(Repository.java:441)
	at org.eclipse.emf.cdo.internal.common.revision.CDORevisionManagerImpl.loadRevisions(CDORevisionManagerImpl.java:352)
	at org.eclipse.emf.cdo.internal.common.revision.CDORevisionManagerImpl.getRevisions(CDORevisionManagerImpl.java:263)
	at org.eclipse.emf.cdo.internal.common.revision.CDORevisionManagerImpl.getRevision(CDORevisionManagerImpl.java:246)
	at org.eclipse.emf.cdo.spi.common.revision.RevisionInfo.execute(RevisionInfo.java:132)
	at org.eclipse.emf.cdo.server.internal.net4j.protocol.LoadRevisionsIndication.responding(LoadRevisionsIndication.java:169)
	at org.eclipse.emf.cdo.server.internal.net4j.protocol.CDOServerIndication.responding(CDOServerIndication.java:133)
	at org.eclipse.net4j.signal.IndicationWithResponse.doExtendedOutput(IndicationWithResponse.java:96)
	at org.eclipse.net4j.signal.Signal.doOutput(Signal.java:296)
	at org.eclipse.net4j.signal.IndicationWithResponse.execute(IndicationWithResponse.java:65)
	at org.eclipse.emf.cdo.server.internal.net4j.protocol.CDOReadIndication.execute(CDOReadIndication.java:36)
	at org.eclipse.net4j.signal.Signal.runSync(Signal.java:251)
	at org.eclipse.net4j.signal.Signal.run(Signal.java:147)
	at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:650)
	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:675)
	at java.lang.Thread.run(Thread.java:595)

!ENTRY org.eclipse.net4j 4 0 2011-03-14 16:01:58.340
!MESSAGE Can not get long id from external ID types
!STACK 0
java.lang.IllegalArgumentException: Can not get long id from external ID types
	at org.eclipse.emf.cdo.common.id.CDOIDUtil.getLong(CDOIDUtil.java:85)
	at org.eclipse.emf.cdo.server.internal.db.mapping.horizontal.DelegatingObjectTypeMapper.getObjectType(DelegatingObjectTypeMapper.java:55)
	at org.eclipse.emf.cdo.server.internal.db.mapping.horizontal.AbstractHorizontalMappingStrategy.readObjectType(AbstractHorizontalMappingStrategy.java:73)
	at org.eclipse.emf.cdo.server.internal.db.DBStoreAccessor.readObjectType(DBStoreAccessor.java:170)
	at org.eclipse.emf.cdo.server.internal.db.DBStoreAccessor.getObjectType(DBStoreAccessor.java:187)
	at org.eclipse.emf.cdo.server.internal.db.DBStoreAccessor.readRevision(DBStoreAccessor.java:207)
	at org.eclipse.emf.cdo.internal.server.Repository.loadRevisions(Repository.java:441)
	at org.eclipse.emf.cdo.internal.common.revision.CDORevisionManagerImpl.loadRevisions(CDORevisionManagerImpl.java:352)
	at org.eclipse.emf.cdo.internal.common.revision.CDORevisionManagerImpl.getRevisions(CDORevisionManagerImpl.java:263)
	at org.eclipse.emf.cdo.internal.common.revision.CDORevisionManagerImpl.getRevision(CDORevisionManagerImpl.java:246)
	at org.eclipse.emf.cdo.spi.common.revision.RevisionInfo.execute(RevisionInfo.java:132)
	at org.eclipse.emf.cdo.server.internal.net4j.protocol.LoadRevisionsIndication.responding(LoadRevisionsIndication.java:169)
	at org.eclipse.emf.cdo.server.internal.net4j.protocol.CDOServerIndication.responding(CDOServerIndication.java:133)
	at org.eclipse.net4j.signal.IndicationWithResponse.doExtendedOutput(IndicationWithResponse.java:96)
	at org.eclipse.net4j.signal.Signal.doOutput(Signal.java:296)
	at org.eclipse.net4j.signal.IndicationWithResponse.execute(IndicationWithResponse.java:65)
	at org.eclipse.emf.cdo.server.internal.net4j.protocol.CDOReadIndication.execute(CDOReadIndication.java:36)
	at org.eclipse.net4j.signal.Signal.runSync(Signal.java:251)
	at org.eclipse.net4j.signal.Signal.run(Signal.java:147)
	at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:650)
	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:675)
	at java.lang.Thread.run(Thread.java:595)


Reproducible: Always
Comment 1 Eike Stepper CLA 2011-03-14 11:36:34 EDT
The stack trace implies that a CDOObject has been assigned an external ID, which should be impossible. The question is what leads to this malicious LoadRevisionsRequest. Can you set a breakpoint in LoadRevisionsRequest.requesting(CDODataOutput) and paste the stack trace here?
Comment 2 Stephane fournier CLA 2011-03-17 08:55:58 EDT
(In reply to comment #1)
> The stack trace implies that a CDOObject has been assigned an external ID,
> which should be impossible. The question is what leads to this malicious
> LoadRevisionsRequest. Can you set a breakpoint in
> LoadRevisionsRequest.requesting(CDODataOutput) and paste the stack trace here?

In LoadRevisionsRequest.requesting(CDODataOutput),
ids : [oid:2da551b-0614-4818-ae9f-0aa5f51c7772]
fetchRules for these ids == null.

Stack trace :

LoadRevisionsRequest.requesting(CDODataOutput) line: 126	
LoadRevisionsRequest(CDOClientRequest<RESULT>).requesting(ExtendedDataOutputStream) line: 66	
LoadRevisionsRequest(RequestWithConfirmation<RESULT>).doExtendedOutput(ExtendedDataOutputStream) line: 117	
LoadRevisionsRequest(Signal).doOutput(BufferOutputStream) line: 296	
LoadRevisionsRequest(RequestWithConfirmation<RESULT>).doExecute(BufferInputStream, BufferOutputStream) line: 102	
LoadRevisionsRequest(SignalActor).execute(BufferInputStream, BufferOutputStream) line: 51	
LoadRevisionsRequest(Signal).runSync() line: 251	
CDOClientProtocol(SignalProtocol<INFRA_STRUCTURE>).startSignal(SignalActor, long) line: 396	
LoadRevisionsRequest(RequestWithConfirmation<RESULT>).doSend(long) line: 87	
LoadRevisionsRequest(RequestWithConfirmation<RESULT>).send() line: 73	
CDOClientProtocol.send(RequestWithConfirmation<RESULT>) line: 397	
CDOClientProtocol.send(LoadRevisionsRequest) line: 430	
CDOClientProtocol.loadRevisions(List<RevisionInfo>, CDOBranchPoint, int, int) line: 160	
DelegatingSessionProtocol.loadRevisions(List<RevisionInfo>, CDOBranchPoint, int, int) line: 522	
CDORevisionManagerImpl.loadRevisions(List<RevisionInfo>, CDOBranchPoint, int, int) line: 352	
CDORevisionManagerImpl.getRevisions(List<CDOID>, CDOBranchPoint, int, int, boolean, SyntheticCDORevision[]) line: 263	
CDORevisionManagerImpl.getRevision(CDOID, CDOBranchPoint, int, int, boolean, SyntheticCDORevision[]) line: 246	
CDORevisionManagerImpl.getRevision(CDOID, CDOBranchPoint, int, int, boolean) line: 239	
CDOTransactionImpl(CDOViewImpl).getRevision(CDOID, boolean) line: 317	
CDOTransactionImpl(AbstractCDOView).createObject(CDOID) line: 749	
CDOTransactionImpl(AbstractCDOView).getObject(CDOID, boolean) line: 668	
CDOTransactionImpl.getObject(CDOID, boolean) line: 992	
CDOTransactionImpl.getObject(CDOID, boolean) line: 1	
CDOResourceImpl.getEObject(String) line: 596	
MelodyValidatorAdapter(EObjectValidator).validate_UniqueID(EObject, DiagnosticChain, Map<Object,Object>) line: 1801	
MelodyValidatorAdapter(EObjectValidator).validate_EveryDefaultConstraint(EObject, DiagnosticChain, Map<Object,Object>) line: 373
Comment 3 Eike Stepper CLA 2011-03-17 08:58:05 EDT
May be a bug in CDOResourceImpl.getEObject(String) related to ID attributes. I'm about to leave for Santa Clara and will not return before April. But I'll keep this issue in the queue..
Comment 4 Eike Stepper CLA 2011-04-10 04:44:05 EDT
Stéphane, can you attach a test case for our test framework, so that I can reproduce the problem?
Comment 5 Stephane fournier CLA 2011-04-20 16:01:24 EDT
(In reply to comment #4)
> Stéphane, can you attach a test case for our test framework, so that I can
> reproduce the problem?

It is really easy to reproduce the issue.
Please use your own metamodel with an object that contains a string attribute set as an ID (from EMF point of view). Generate java API for this meta-model.
Create a dummy model instance by code that instantiates many objects and set their id with generated string by java.util.UUID.randomUUID() (call the randomUUID at each set).

Import this xmi model in a CDO repo (based on a DB store H2 for instance).
From the editor opened by CDO as a result of the import operation, select the root model element, right click on it and run the standard EMF Validation action. 
This action reveals the bug.
Comment 6 Eike Stepper CLA 2011-04-21 00:41:42 EDT
Committed revision 7632:
- trunk/plugins/org.eclipse.emf.cdo.tests.model3
Comment 7 Eike Stepper CLA 2011-04-21 00:43:00 EDT
Committed revision 7633:
- trunk/plugins/org.eclipse.emf.cdo.tests.model3
Comment 8 Eike Stepper CLA 2011-04-21 00:45:50 EDT
Committed revision 7632
Committed revision 7633
Comment 9 Eike Stepper CLA 2011-04-21 01:12:35 EDT
Committed revision 7634:
- trunk/plugins/org.eclipse.emf.cdo.tests
Comment 10 Eike Stepper CLA 2011-04-21 01:34:44 EDT
Created attachment 193777 [details]
Screenshot

Neither with the procedure you've described nor with org.eclipse.emf.cdo.tests.bugzilla.Bugzilla_339908_Test I can reproduce this or a similar problem.

The first stack trace in the bug description implies that the server executes a normal LoadRevisionsRequest. That means, the client holds an object and is currently accessing one of the references of this object. The CDORevision of the object contains a CDOID for the target of the reference and the client can not find the adequate target revision in its cache. Hence it asks the server to load/provide this target revision by sending the target CDOID.

It appears that in your case this CDOID is an external ID, which is absolutely contradictory, because external IDs are resolved by the client's resourceset to something in a non-CDOResource.

The question is "why does your resourceset resolve this external ID to an object in your repo?" and I fear without a test case that reproduces this behaviour I can not answer it. Maybe you can ZIP up the relevant *executable projects* and send them to me privately?
Comment 11 Stephane fournier CLA 2011-04-22 18:32:23 EDT
(In reply to comment #10)
> Created attachment 193777 [details]
> Screenshot
> 
> Neither with the procedure you've described nor with
> org.eclipse.emf.cdo.tests.bugzilla.Bugzilla_339908_Test I can reproduce this or
> a similar problem.
> 
> The first stack trace in the bug description implies that the server executes a
> normal LoadRevisionsRequest. That means, the client holds an object and is
> currently accessing one of the references of this object. The CDORevision of
> the object contains a CDOID for the target of the reference and the client can
> not find the adequate target revision in its cache. Hence it asks the server to
> load/provide this target revision by sending the target CDOID.
> 
> It appears that in your case this CDOID is an external ID, which is absolutely
> contradictory, because external IDs are resolved by the client's resourceset to
> something in a non-CDOResource.
> 
> The question is "why does your resourceset resolve this external ID to an
> object in your repo?" and I fear without a test case that reproduces this
> behaviour I can not answer it. Maybe you can ZIP up the relevant *executable
> projects* and send them to me privately?

I will ask to do that for sure.
Comment 12 Stefan Schalomon CLA 2011-07-18 13:01:42 EDT
(In reply to comment #10)
> The question is "why does your resourceset resolve this external ID to an
> object in your repo?" and I fear without a test case that reproduces this
> behaviour I can not answer it.

Eike,
we're observing the problem here with our custom editors as well. The root cause seems to be EObjectValidator.validate_UniqueID(EObject, DiagnosticChain, Map<Object, Object>) and the way it deals with IDs.

Essentially, validate_UniqueID does the following:
String id = EcoreUtil.getID(eObject);
Resource resource = eObject.eResource();
EObject otherEObject = resource.getEObject(id);

That is, there's a hardcoded assumption that an object's unique ID can be directly used as an URI fragment. But if I remember correctly there's no such contract.

In our case the unique ID is a base32 encoded UUID like 'EABCDEFGHIJKLMNOPQRSTUV123'. If one dares to call CDOResourceImpl.getEObject(String) with this ID as fragment, CDOIDUtil.read(String) internally inspects the 1st character to deceide what kind of OID to create. Unfortunately, that would be an external OID in this case. The resource's CDOView is then queried for an object with this OID and the error described by Stéphane appears.

As a quick workaround, I simply disabled the whole validate_UniqueID check as I don't need it anyway. But I think a bug should be filed against EObjectValidator.
Comment 13 Eike Stepper CLA 2012-06-05 07:29:43 EDT
Moving all open bug reports to 4.1 because the release is very near and it's hghly unlikely that there will be spare time to address 4.0 problems.

Please make sure that your patches can be applied against the master branch and that your problem is not already fixed there!!!
Comment 14 Eike Stepper CLA 2012-08-14 22:53:06 EDT
Moving all open issues to 4.2. Open bugs can be ported to 4.1 maintenance after they've been fixed in master.
Comment 15 Eike Stepper CLA 2012-10-31 14:29:41 EDT
In the meantime we've got changes in CDOResourceImpl.getEObject(uriFragment) and we've got client-assigned CDOIDs (through a CDOIDGenerator in the CDOSession).

Please reopen this bug if you feel a need.