Community
Participate
Working Groups
Real decision appraently doesn't work in QVTo. The problem is probably in the URIs. e.g multiply is: referredOperation="ecore:EOperation http://www.eclipse.org/ocl/1.1.0/oclstdlib.ecore#/0/Real_Class/*" while divide is: referredOperation="ecore:EOperation http://www.eclipse.org/ocl/1.1.0/oclstdlib.ecore#/0/Real_Class/%2F" I suspect that the %2F didn't translate back to "/".
Is there any reproduction scenario or a failing test case that helps in tracing the issue?
The original email message from Nicolas Rouquette. Ed, A colleague told me that the Real division operation in QVTO doesn't work. Upon closer inspection, I found that the URI of the referred operation is peculiar for Real division, i.e., "/": I made a simple test: transformation RealDivisionTest(); main() { var d1 : Real = "1.5".toReal(); var d2 : Real = "2.0".toReal(); var d3 : Real = d1 * d2; log("d3 = " + d3.toString()); var d4 : Real = d1 / d2; log("d4 = " + d4.toString()); } This compiles to the following: <?xml version="1.0" encoding="UTF-8"?> <qvtoperational.expr:OperationalTransformation xmi:version="2.0" xmlns:xmi="http://www.omg.org/XMI" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:ecore="http://www.eclipse.org/emf/2002/Ecore" xmlns:eimpocl="http://www.eclipse.org/qvt/1.0/ImperativeOCL" xmlns:ocl.ecore="http://www.eclipse.org/ocl/1.1.0/Ecore" xmlns:qvtoperational.expr="http://www.eclipse.org/qvt/1.0.0/Operational/Expressions" name="RealDivisionTest" instanceClassName="org.eclipse.m2m.internal.qvt.oml.evaluator.TransformationInstance" eSuperTypes="http://www.eclipse.org/m2m/qvt/oml/1.0.0/Stdlib#//Transformation" nsPrefix="RealDivisionTest" entry="#//main"> <xmi:Extension extender="http://www.eclipse.org/qvt/1.0.0/Operational/Expressions/debugInfo"> <sourceURI>RealDivisionTest.qvto</sourceURI> <offsets>0,e1,24,bd,5,b8,9,19,.,.,c,d,0,4,15,19,.,.,c,d,0,4,15,12,.,.,c,6,0,1,5,1,5,1b,4,16,0,6,a,c,0,1,15,12,.,.,c,6,0,1,5,1,5,1b,4,16,0,6,a,c,0,1,.,.</offsets> <lineBreaks>a,22,1,2b,22,4c,3c,6b,56,8a,58</lineBreaks> </xmi:Extension> <eOperations xsi:type="qvtoperational.expr:EntryOperation" name="main" eType="ocl.ecore:VoidType http://www.eclipse.org/ocl/1.1.0/oclstdlib.ecore#/0/OclVoid"> <body> <content xsi:type="eimpocl:VariableInitExp" name="d1" eType="ocl.ecore:PrimitiveType http://www.eclipse.org/ocl/1.1.0/oclstdlib.ecore#/0/Real"> <referredVariable name="d1" eType="ocl.ecore:PrimitiveType http://www.eclipse.org/ocl/1.1.0/oclstdlib.ecore#/0/Real"> <initExpression xsi:type="ocl.ecore:OperationCallExp" eType="ocl.ecore:PrimitiveType http://www.eclipse.org/ocl/1.1.0/oclstdlib.ecore#/0/Real" referredOperation="ecore:EOperation http://www.eclipse.org/ocl/1.1.0/oclstdlib.ecore#/0/String_Class/toReal"> <source xsi:type="ocl.ecore:StringLiteralExp" eType="ocl.ecore:PrimitiveType http://www.eclipse.org/ocl/1.1.0/oclstdlib.ecore#/0/String" stringSymbol="1.5"/> </initExpression> </referredVariable> </content> <content xsi:type="eimpocl:VariableInitExp" name="d2" eType="ocl.ecore:PrimitiveType http://www.eclipse.org/ocl/1.1.0/oclstdlib.ecore#/0/Real"> <referredVariable name="d2" eType="ocl.ecore:PrimitiveType http://www.eclipse.org/ocl/1.1.0/oclstdlib.ecore#/0/Real"> <initExpression xsi:type="ocl.ecore:OperationCallExp" eType="ocl.ecore:PrimitiveType http://www.eclipse.org/ocl/1.1.0/oclstdlib.ecore#/0/Real" referredOperation="ecore:EOperation http://www.eclipse.org/ocl/1.1.0/oclstdlib.ecore#/0/String_Class/toReal"> <source xsi:type="ocl.ecore:StringLiteralExp" eType="ocl.ecore:PrimitiveType http://www.eclipse.org/ocl/1.1.0/oclstdlib.ecore#/0/String" stringSymbol="2.0"/> </initExpression> </referredVariable> </content> <content xsi:type="eimpocl:VariableInitExp" name="d3" eType="ocl.ecore:PrimitiveType http://www.eclipse.org/ocl/1.1.0/oclstdlib.ecore#/0/Real"> <referredVariable name="d3" eType="ocl.ecore:PrimitiveType http://www.eclipse.org/ocl/1.1.0/oclstdlib.ecore#/0/Real"> <initExpression xsi:type="ocl.ecore:OperationCallExp" eType="ocl.ecore:PrimitiveType http://www.eclipse.org/ocl/1.1.0/oclstdlib.ecore#/0/Real" referredOperation="ecore:EOperation http://www.eclipse.org/ocl/1.1.0/oclstdlib.ecore#/0/Real_Class/*"> <source xsi:type="ocl.ecore:VariableExp" name="d1" eType="ocl.ecore:PrimitiveType http://www.eclipse.org/ocl/1.1.0/oclstdlib.ecore#/0/Real" referredVariable="#//main/@body/@content.0/d1"/> <argument xsi:type="ocl.ecore:VariableExp" name="d2" eType="ocl.ecore:PrimitiveType http://www.eclipse.org/ocl/1.1.0/oclstdlib.ecore#/0/Real" referredVariable="#//main/@body/@content.1/d2"/> </initExpression> </referredVariable> </content> <content xsi:type="eimpocl:LogExp" name="log"> <argument xsi:type="ocl.ecore:OperationCallExp" eType="ocl.ecore:PrimitiveType http://www.eclipse.org/ocl/1.1.0/oclstdlib.ecore#/0/String" referredOperation="ecore:EOperation http://www.eclipse.org/m2m/qvt/oml/1.0.0/Stdlib#//String/+"> <source xsi:type="ocl.ecore:StringLiteralExp" eType="ocl.ecore:PrimitiveType http://www.eclipse.org/ocl/1.1.0/oclstdlib.ecore#/0/String" stringSymbol="d3 = "/> <argument xsi:type="ocl.ecore:OperationCallExp" eType="ocl.ecore:PrimitiveType http://www.eclipse.org/ocl/1.1.0/oclstdlib.ecore#/0/String" referredOperation="ecore:EOperation http://www.eclipse.org/m2m/qvt/oml/1.0.0/Stdlib#//Real/toString"> <source xsi:type="ocl.ecore:VariableExp" name="d3" eType="ocl.ecore:PrimitiveType http://www.eclipse.org/ocl/1.1.0/oclstdlib.ecore#/0/Real" referredVariable="#//main/@body/@content.2/d3"/> </argument> </argument> </content> <content xsi:type="eimpocl:VariableInitExp" name="d4" eType="ocl.ecore:PrimitiveType http://www.eclipse.org/ocl/1.1.0/oclstdlib.ecore#/0/Real"> <referredVariable name="d4" eType="ocl.ecore:PrimitiveType http://www.eclipse.org/ocl/1.1.0/oclstdlib.ecore#/0/Real"> <initExpression xsi:type="ocl.ecore:OperationCallExp" eType="ocl.ecore:PrimitiveType http://www.eclipse.org/ocl/1.1.0/oclstdlib.ecore#/0/Real" referredOperation="ecore:EOperation http://www.eclipse.org/ocl/1.1.0/oclstdlib.ecore#/0/Real_Class/%2F"> <source xsi:type="ocl.ecore:VariableExp" name="d1" eType="ocl.ecore:PrimitiveType http://www.eclipse.org/ocl/1.1.0/oclstdlib.ecore#/0/Real" referredVariable="#//main/@body/@content.0/d1"/> <argument xsi:type="ocl.ecore:VariableExp" name="d2" eType="ocl.ecore:PrimitiveType http://www.eclipse.org/ocl/1.1.0/oclstdlib.ecore#/0/Real" referredVariable="#//main/@body/@content.1/d2"/> </initExpression> </referredVariable> </content> <content xsi:type="eimpocl:LogExp" name="log"> <argument xsi:type="ocl.ecore:OperationCallExp" eType="ocl.ecore:PrimitiveType http://www.eclipse.org/ocl/1.1.0/oclstdlib.ecore#/0/String" referredOperation="ecore:EOperation http://www.eclipse.org/m2m/qvt/oml/1.0.0/Stdlib#//String/+"> <source xsi:type="ocl.ecore:StringLiteralExp" eType="ocl.ecore:PrimitiveType http://www.eclipse.org/ocl/1.1.0/oclstdlib.ecore#/0/String" stringSymbol="d4 = "/> <argument xsi:type="ocl.ecore:OperationCallExp" eType="ocl.ecore:PrimitiveType http://www.eclipse.org/ocl/1.1.0/oclstdlib.ecore#/0/String" referredOperation="ecore:EOperation http://www.eclipse.org/m2m/qvt/oml/1.0.0/Stdlib#//Real/toString"> <source xsi:type="ocl.ecore:VariableExp" name="d4" eType="ocl.ecore:PrimitiveType http://www.eclipse.org/ocl/1.1.0/oclstdlib.ecore#/0/Real" referredVariable="#//main/@body/@content.4/d4"/> </argument> </argument> </content> </body> </eOperations> <ownedVariable name="this" eType="#/"/> </qvtoperational.expr:OperationalTransformation> Notice how the URIs of the operations for Real * and Real / are: <content xsi:type="eimpocl:VariableInitExp" name="d3" eType="ocl.ecore:PrimitiveType http://www.eclipse.org/ocl/1.1.0/oclstdlib.ecore#/0/Real"> <referredVariable name="d3" eType="ocl.ecore:PrimitiveType http://www.eclipse.org/ocl/1.1.0/oclstdlib.ecore#/0/Real"> <initExpression xsi:type="ocl.ecore:OperationCallExp" eType="ocl.ecore:PrimitiveType http://www.eclipse.org/ocl/1.1.0/oclstdlib.ecore#/0/Real" referredOperation="ecore:EOperation http://www.eclipse.org/ocl/1.1.0/oclstdlib.ecore#/0/Real_Class/*"> <source xsi:type="ocl.ecore:VariableExp" name="d1" eType="ocl.ecore:PrimitiveType http://www.eclipse.org/ocl/1.1.0/oclstdlib.ecore#/0/Real" referredVariable="#//main/@body/@content.0/d1"/> <argument xsi:type="ocl.ecore:VariableExp" name="d2" eType="ocl.ecore:PrimitiveType http://www.eclipse.org/ocl/1.1.0/oclstdlib.ecore#/0/Real" referredVariable="#//main/@body/@content.1/d2"/> </initExpression> </referredVariable> </content> vs. <content xsi:type="eimpocl:VariableInitExp" name="d4" eType="ocl.ecore:PrimitiveType http://www.eclipse.org/ocl/1.1.0/oclstdlib.ecore#/0/Real"> <referredVariable name="d4" eType="ocl.ecore:PrimitiveType http://www.eclipse.org/ocl/1.1.0/oclstdlib.ecore#/0/Real"> <initExpression xsi:type="ocl.ecore:OperationCallExp" eType="ocl.ecore:PrimitiveType http://www.eclipse.org/ocl/1.1.0/oclstdlib.ecore#/0/Real" referredOperation="ecore:EOperation http://www.eclipse.org/ocl/1.1.0/oclstdlib.ecore#/0/Real_Class/%2F"> <source xsi:type="ocl.ecore:VariableExp" name="d1" eType="ocl.ecore:PrimitiveType http://www.eclipse.org/ocl/1.1.0/oclstdlib.ecore#/0/Real" referredVariable="#//main/@body/@content.0/d1"/> <argument xsi:type="ocl.ecore:VariableExp" name="d2" eType="ocl.ecore:PrimitiveType http://www.eclipse.org/ocl/1.1.0/oclstdlib.ecore#/0/Real" referredVariable="#//main/@body/@content.1/d2"/> </initExpression> </referredVariable> </content> When I execute this, the QVTO interpreter manages to resolve the URI for Real multiplication -- i.e., http://www.eclipse.org/ocl/1.1.0/oclstdlib.ecore#/0/Real_Class/* It can't resolve the operation for Real division: http://www.eclipse.org/ocl/1.1.0/oclstdlib.ecore#/0/Real_Class/%2F This explains why the evaluation of "d1 / d2" returns an OclInvalid result. What's worse is that if I edit the compiled QVTOX file with a sample reflective ecore editor, then I can change the referredOperation from null() -- i.e., unresolved proxy -- to, e.g., Real/, etc... but when I save, i get the same XMI. So I think there is something broken somewhere deeper about the handling of "%2F". If I wanted to change the name of Real division from "/" to, e.g., "div", where would do I have to make that change? I have org.eclipse.ocl & org.eclipse.ocl.ecore checked out from R3.0 maintenance (since I'm using Eclipse Helios QVTO for our integration with MagicDraw). - Nicolas.
Created attachment 207632 [details] Sample ecore referencing Real:/(...) I've created the little sample ecore attached, creating an EAnnotation that references the / operation of Real using the supposedly offending URI. I can open this ecore file successfully using the Sample Ecore Model Editor. When I drill down to the EAnnotation element, the oclstdlib.ecore resource is loaded successfully and the reference seems to resolve properly. It seems as if this is at least not a general EMF / Ecore / OCL issue. Could it be related to the specific QVTO environment somehow?
I would expect Ecore to be consistent, The problem is that referredOperations in the legacy code are special URIs. I've never understood them, but by the time they get through to EvaluationVisitorImpl they're names. I suspect there is a naive prefix trim at some point.
Haven't checked the code yet, but from all I remember, referredOperation is a regular reference that the evaluator combines with the operation code, an int stored on the OperationCallExp, usually by the parser. The mapping to/from opCode to operation happens by means of OCLStandardLibraryUtil. It actually happens via the operation's name attribute, but that is properly contained in the EOperation element in the oclstdlib.ecore. I can't see any code that is based on the EOperation's URI.
It works in Acceleo, because in AcceleoEvaluationVisitor.visitOperationCallExp there is some workaround code. /* * OCL used "/" as operation name for the division ... Which means divisions will never be * serializable : its URI is invalid. We'll then try and "trick" OCL for these. */ if (((EObject)callExp.getReferredOperation()).eIsProxy()) { URI uri = ((InternalEObject)callExp.getReferredOperation()).eProxyURI(); if (uri.fragment() != null && uri.fragment().endsWith("%2F")) { //$NON-NLS-1$ callExp.setOperationCode(PredefinedType.DIVIDE); } } A shame they didn't raise a Bugzilla. I'm not sure that the diagnosis is accurate. As I discovered at the weekend when my Internet connection was down, the true problem may be a failure to register "http://www.eclipse.org/ocl/1.1.0/oclstdlib.ecore" (Bug 364797) which provokes an Internet access before leaving a proxy unchanged. For most operations the OCL code works on the proxies quite happily, but obviously as a proxy %2F didn't get translated. There is an oclstdlib.ecore so potentially the proxies may be resolvable. However, since non-registration is now a customary practice, perhaps all copies of OperationCallExpImpl.getOperationCode() should be tested for both registered and unregistered usage.
(In reply to comment #6) > /* > * OCL used "/" as operation name for the division ... Which means > divisions will never be > * serializable : its URI is invalid. We'll then try and "trick" OCL > for these. > */ The test model I attached seems to suggest the contrary. The / operation reference serializes and deserializes fine. Could this be a version issue of some sort? Which EMF and which Ecore version is used when the bug occurs? Can we get a failing test case for the current OCL code base? > However, since non-registration is now a customary practice, perhaps all copies > of OperationCallExpImpl.getOperationCode() should be tested for both registered > and unregistered usage. I don't understand. Either the URI pointing to the EOperation can be resolved or it can't. If the URI for the * operation can be resolved then at least the little test model suggests that it should also work for /. I wonder how URI resolution works differently in QVTO as compared to regular EMF/Ecore.
(In reply to comment #6) > It works in Acceleo, because in AcceleoEvaluationVisitor.visitOperationCallExp > there is some workaround code. Yes, I did not see this bug report soon enough, but I would have been able to save you some time digging. > A shame they didn't raise a Bugzilla. We do not raise a bugzilla for every single bug, and this in particular was thought to be because of our "not-so-standard" usage of OCL (it was not really meant to be serialized out of an EAnnotation IIRC). > I'm not sure that the diagnosis is accurate. I am unsure of what really happens here, but I do know that the reference as it is cannot be resolved, which can be seen in our workaround (if (...eIsProxy()). It might be because of the way we serialize our resources, it might be because of the way we load them, it might be because of the reference itself (maybe we should encode it beforehand?)... IIRC, this bug did not present itself if "oclstdlib.ecore" had been loaded (we tried by opening it in an editor) before our resource. The fact was : the OperationCall referred to a proxy, and the operation code was not set. > As I discovered at the weekend when my Internet connection was down, the true > problem may be a failure to register > "http://www.eclipse.org/ocl/1.1.0/oclstdlib.ecore" (Bug 364797) which provokes > an Internet access before leaving a proxy unchanged. We force the registration of that one in all of our generators; resourceSet.getPackageRegistry().put("http://www.eclipse.org/ocl/1.1.0/oclstdlib.ecore", getOCLStdLibPackage()); was not enough. Fully loading the oclstdlib.ecore resource itself in an editor may have been, I am not sure.
(In reply to comment #7) > The test model I attached seems to suggest the contrary. The / operation > reference serializes and deserializes fine. Could this be a version issue of > some sort? Which EMF and which Ecore version is used when the bug occurs? Can > we get a failing test case for the current OCL code base? I do not have time to make the necessary tests, but removing the workaround we have in Acceleo should be enough to reproduce the failure. Ed might want to try that way.
(In reply to comment #6) > I'm not sure that the diagnosis is accurate. (In reply to comment #7) > The test model I attached seems to suggest the contrary. The / operation > reference serializes and deserializes fine. Could this be a version issue of > some sort? Which EMF and which Ecore version is used when the bug occurs? Can > we get a failing test case for the current OCL code base? Yes. I think that symmetric serialization/deserialization in EMF is probably fine. Hence that symmetric serialization is not the problem. I think what QVTo and Acceleo (prior to the workaround) experience is asymmetric deserialization after proxy resolution fails, and so OCL is using %2F rather than /. (In reply to comment #8) > We force the registration of that one in all of our generators; > > resourceSet.getPackageRegistry().put("http://www.eclipse.org/ocl/1.1.0/oclstdlib.ecore", > getOCLStdLibPackage()); > > was not enough. Fully loading the oclstdlib.ecore resource itself in an editor > may have been, I am not sure. No that won't work, since the legacy oclstdlib.ecore is not a true model; it has no Java EPackage. You have to force the model load via: URIConverter.URI_MAP.put(URI.createURI("http://www.eclipse.org/ocl/1.1.0/oclstdlib.ecore"), URI.createPlatformPluginURI("/org.eclipse.ocl.ecore/model/oclstdlib.ecore", true));