Eclipse Community Forums
Forum Search:

Search      Help    Register    Login    Home
Home » Modeling » OCL » Operations from OCL StdLib have an EDataType instead of UMLPrimitiveType
Operations from OCL StdLib have an EDataType instead of UMLPrimitiveType [message #1757807] Mon, 20 March 2017 08:05 Go to next message
Denis Nikiforov is currently offline Denis NikiforovFriend
Messages: 170
Registered: August 2013
Senior Member
Hi

I've updated Eclipse OCL to the latest milestone 6.3.0M6. And it seems that something was broken/changed since 6.3.0.

Equality operator has EDataType::Boolean type instead of UMLPrimitiveType::Boolean type.

Here is a test code:

    public static void main(String[] args) {
        final String input = "model/test.uml";

        ResourceSet rs = new ResourceSetImpl();
        EssentialOCLStandaloneSetup.doSetup();
        org.eclipse.ocl.pivot.uml.UMLStandaloneSetup.init();
        OCL ocl = OCL.newInstance(rs);

        Resource resource = ocl.getResourceSet().getResource(createFileURI(input), true);

        Model uml = (Model)EcoreUtil.getObjectByType(resource.getContents(), UMLPackage.eINSTANCE.getModel());
        try {
            Class person = (Class)uml.getPackagedElement("Person");
            org.eclipse.ocl.pivot.Class personAS = ocl.getMetamodelManager().getASOf(org.eclipse.ocl.pivot.Class.class, person);
            System.out.println("PersonAS: " + personAS);

            org.eclipse.ocl.pivot.Property nameAttrAS = personAS.getOwnedProperties().get(0);

            // I get UMLPrimitiveType::String type here. It is ok.
            System.out.println("DataType: " + nameAttrAS.getType().getESObject());

            ExpressionInOCL expr = ocl.createQuery(personAS, "self.name = ''");
            System.out.println("Expression: " + expr);

            // But I get EDataType::Boolean here. I think it is a bug.
            // I think that the type was UMLPrimitiveType::Boolean in previous versions
            System.out.println("Type: " + expr.getType().getESObject());
        }
        catch (Exception e) {
            e.printStackTrace();
        }
    }

    private static URI createFileURI(String relativePath)
    {
        return URI.createFileURI(new File(relativePath).getAbsolutePath());
    }


Full project is here: https://github.com/AresEkb/ocl_getesobject_test

When I work with an UML model I expect UML primitive types instead of Ecore types.
Re: Operations from OCL StdLib have an EDataType instead of UMLPrimitiveType [message #1757822 is a reply to message #1757807] Mon, 20 March 2017 10:45 Go to previous messageGo to next message
Ed Willink is currently offline Ed WillinkFriend
Messages: 5534
Registered: July 2009
Senior Member
Hi

Hm. I think what you see is correct, but perhaps it could be more correct. Perhaps if I provide some background you can identify what might be better for your larger use case.

I think this has changed, but only in the sense that the sense that the order of elements returned by a Set iterator can change. I recall fixing a bug whereby the UML esObject could be uninitialized.

"esObject" / "getESObject" unfortunately lacks a comment defining its intended API, so there is just the obvious interpretation of an External Syntax Object.

Unfortunately UML has no realistic implementation classes and so Eclipse UML2 uses a mapping to Ecore classes that leaves an ambiguity as to whether UML or the UML2Ecore Ecore is the external syntax.
I try to make the Pivot OCL support for UML support for UML rather than support for bowdlerized UML, so I try to make the esObject for UML the UML alternative.
I regard getESObject() as 'internal API' but lack the time / skill to accurately annotate internal API for users without making OCL unuseable for QVTd.

Eclipse UML2's Ecore introduces variant UML models with variant URIs. This is mostly invisible but is very embarrassing for profile which have the wrong meta-URI.

For your "name" attribute the original UML is available so the UML type can be returned.

For your expression, you are in the OCL world and so the OCL type is returned. Perhaps something, possibly the currently deprecated UMLOCL 'facade', should support conversion of returned as well as consumed objects.

Perhaps a new public API is needed. The IdResolver has a UML-specific derivation so this may be where a UML-flavoured API override could be provided.

-----

The concept of Primitive is left incredibly vague by UML. Good, it is a very abstract analysis concept that does not restrict design/implementation. Bad, implementations have to reify it.

For a Papyrus Boolean we may have many 'definition's of the concept:
2 Java variants
2 Ecore variants
1 OMG UML variant
1 Eclipse UML2 variant
1 SysML variant
1 OCL variant
N * user-defined variants

If these are not the same unified Boolean type, expression evaluation is almost unuseable.

The Pivot OCL introduces some relevant innovations/solutions.

1) In order to support open classes, multiple definitions are merged by simple hierarchical collision wrt same-URIed packages

2) All non-TemplateParameter types are Classes (i.e. can have operations and attributes).

3) The namespace of PrimitiveTypes and CollectionTypes facilitates incorporation within a partial model, distinct namespaces do not create distinct Primitive/CollectionTypes.

4) A virtual meta-model URI can aggregate a number of distinct URIs thereby by merging OMG UML, Eclipse UML2, Pivot OCL

Therefore for each Package/Class there is a CompletePackage/CompleteClass that supervises the merge within an overall CompleteModel.

If you examine the CompleteClass for each of your types, you find a dual type, one from the UML2Ecore types package, one from the OCL standard library

PrimitiveCompletePackage primitiveCompletePackage = ocl.getEnvironmentFactory().getCompleteModel().getPrimitiveCompletePackage();
CompleteClass attrCompleteString = primitiveCompletePackage.getCompleteClass(PivotUtil.getClass(nameAttrAS));
System.out.println("attrCompleteBoolean: " + attrCompleteString);
for (org.eclipse.ocl.pivot.Class attrString : attrCompleteString.getPartialClasses()) {
System.out.println("\t" + attrString.getOwningPackage().getURI() + " " + attrString + " " + attrString.getESObject());
}

Regards

Ed Willink
Re: Operations from OCL StdLib have an EDataType instead of UMLPrimitiveType [message #1757874 is a reply to message #1757822] Tue, 21 March 2017 06:51 Go to previous messageGo to next message
Denis Nikiforov is currently offline Denis NikiforovFriend
Messages: 170
Registered: August 2013
Senior Member
Thanks for detailed description!

<description of the full scenario>

My full scenario is as follows. I transform an UML model with OCL constraints to XSD/XSLT/Java/... with XPath expressions. The transformation is writen on QVTo. Also it use a black-box library writen on Java. A source UML model is based mostly on custom UML data types. For example, I have the IndicatorType instead of the UML's Boolean primitive type. Also, I have custom types for strings, numbers, dates, durations, etc.

I need to check types of UML properties and OCL expressions in my QVTo transformations. For example, in the following expression I need to check that the LHS and the RHS have the same or compatible types:
address.postalCode = '12345'

The type of address.postalCode is CodeType. The type of string literal is String primitive type.
QVTo transformations knows that these type are compatible, and so the comparision is allowed.

Also the QVTo transformation checks the type of the overall OCL expression. It must have either Boolean primitive type or custom IndicatorType.

For me the ideal solution is to use only my custom data types defined in the UML model, and not to use UML or OCL primitive types at all. It would be great If I could map somehow the custom IndicatorType to the Boolean primitive type, the custom TextType to the String primitive type. It would save me from the necessity to declare substring(), size() and other standard operations for my custom types. Although it is not so difficult to declare them. It's more difficult to extend primitive types. For example I can't declare a String::toDate() operation for the primitive type, that will allow me to write '2017-03-21'.toDate(). Also I can't declare custom iterators for standard collection types. For example, I need to declare the iterator which will join strings contained in a collection of strings. But as I see I can't merge custom UML types with standard primitive or collection types. I need to extend OCL StdLib ( https://www.eclipse.org/forums/index.php/t/1084494/ ).

For now there is a mix of custom UML types and primitive types in my OCL expressions. Object properties have custom types. Results of most operations have primitive types.

</description of the full scenario>

Returning to the original problem, I have the following code, which checks whether a type is either custom IndicatorType or Boolean primitive type:

modeltype UML uses 'http://www.eclipse.org/uml2/2.1.0/UML';

query NamedElement::isBooleanType() : Boolean =
    self.isSimpleType('IndicatorType') or self.isPrimitiveType('Boolean');

query NamedElement::isSimpleType(name : String) : Boolean =
    self.getModel().name = 'CustomUMLDataTypes' and self.name = name;

query NamedElement::isPrimitiveType(name : String) : Boolean =
    self.getModel().name = 'PrimitiveTypes' and self.name = name;

It's expected that the type is derived from UML::NamedElement. When I transform OCL expressions I use the following wrapper to check types:

modeltype OCL 'strict' uses 'http://www.eclipse.org/ocl/2015/Pivot';

query NamedElement::isBooleanType() : Boolean =
    self.getESObject().isBooleanType();

    @Operation(contextual=true)
    public static org.eclipse.uml2.uml.NamedElement getESObject(org.eclipse.ocl.pivot.NamedElement el)
    {
        return (org.eclipse.uml2.uml.NamedElement)el.getESObject();
    }

In version 6.3.0 the code was working fine. But now el.getESObject() returns org.eclipse.emf.ecore.impl.EDataTypeImpl, which can't be cast to org.eclipse.uml2.uml.NamedElement. Is it possible to transform somehow UML2Ecore primitive type to a true UML primitive type?

The getPartialClasses() method returns two classes: OCL primitive type (from http://www.eclipse.org/ocl/2015/Library) and UML2Ecore type (from http://www.eclipse.org/uml2/5.0.0/Types). It doesn't return UML primitive type.

What is a right way to check that a type is a specific OCL primitive type?
Re: Operations from OCL StdLib have an EDataType instead of UMLPrimitiveType [message #1757883 is a reply to message #1757874] Tue, 21 March 2017 08:45 Go to previous messageGo to next message
Ed Willink is currently offline Ed WillinkFriend
Messages: 5534
Registered: July 2009
Senior Member
Hi

Your mention of QVTo makes surprised that we are having this discussion. Surely you are using the Classic OCL, not the Pivot, so nothing has changed? But it appears that you are successfully using the Pivot OCL as the 'user' metamodel and the Classic OCL as the tooling metamodel; well done.

If you were using the Pivot OCL to compare, it should hide the complexity of merged types from you. QVTo however does not. Since you are using Java blackboxes it should be possible to write an aType.getCompleteClass() query that does

PrimitiveCompletePackage primitiveCompletePackage = ocl.getEnvironmentFactory().getCompleteModel().getPrimitiveCompletePackage();
return primitiveCompletePackage.getCompleteClass(PivotUtil.getClass(aType));

CompleteClass is now a modeled class so you should be able to compare them successfully with QVTo.

Comment added to https://bugs.eclipse.org/bugs/show_bug.cgi?id=470734 since a Type::completeClass derived property would make your life easy.

If you look at org.eclipse.ocl.pivot.internal.PropertyImpl.isAttribute you can see how autogenerated code creates anExecutor that discovers EnvironmentFactory, CompleteEnvironment, CompleteModel, IdResolver. Your code will run much faster if you ensure that PivotUtilInternal.getExecutor can find your EnvironmentFactory adapting your ASResource rather than creating a new one each time. Probably just needs an ocl.getEnvironmentFactory().adapt(asResource); Faster still if your can pass the EnvironmentFactory directly to the black box.

Regards

Ed Willink
Re: Operations from OCL StdLib have an EDataType instead of UMLPrimitiveType [message #1757884 is a reply to message #1757883] Tue, 21 March 2017 08:55 Go to previous message
Ed Willink is currently offline Ed WillinkFriend
Messages: 5534
Registered: July 2009
Senior Member
Ed Willink wrote on Tue, 21 March 2017 04:45
Your code will run much faster if you ensure that PivotUtilInternal.getExecutor can find your EnvironmentFactory adapting your ASResource


Wrong. Ensure that your ResourceSet has a suitable adapter; it almost certainly does automatically as a side effect of OCL construction.

Regards

Ed Willink
Previous Topic:[Announce] Impact Analyzer deprecation
Next Topic:OCL Codegenerator
Goto Forum:
  


Current Time: Sat Dec 16 05:35:42 GMT 2017

Powered by FUDForum. Page generated in 0.02158 seconds
.:: Contact :: Home ::.

Powered by: FUDforum 3.0.2.
Copyright ©2001-2010 FUDforum Bulletin Board Software