2

I have a class that has a couple of string attributes that contain OCL expressions. I need to query those objects in OCL, and in that OCL I need to evaluate the OCL expression in one of the attributes.

Can this be done?

I guess I'm looking for an OCL operation like <<object>>.eval(<<string>>), where <<string>> would be evaluated in the context of <<object>>, and preferably any OCL variables in the surrounding OCL would be inherited, so they can be referenced by the OCL expression in <<string>>.

As a workaround I suppose I could add a code derived extra attribute that evaluates an attribute's OCL in the context of the object (which might suffice).

Ed Willink
  • 1,205
  • 7
  • 8
Kjell Rilbe
  • 1,331
  • 14
  • 39

2 Answers2

2

You can write custom OCL operations. Here an example:

[EcoOclOperation(typeof(OclEcoId), true)]
public class OclEcoId : OclOperationBase
{
    /// <summary>
    /// Initialisation of the OCL funktion
    /// </summary>
    protected override void Init()
    {
        var parameter = new IOclType[1]
        {
            this.Support.ObjectType,
        };
        this.InternalInit("EcoId", parameter, this.Support.IntegerType);
    }

    /// <summary>
    /// Implementation of the OCL function
    /// </summary>
    /// <param name="parameters">OCL parameters</param>
    public override void Evaluate(IOclOperationParameters parameters)
    {
        var iObject = parameters.Values[0].Element as IObject;
        if (iObject != null && iObject.AsObject != null)
        {
            var ecoid = iObject.EcoID();
            this.Support.MakeNewInteger(parameters.Result, int.Parse(ecoid));
        }
    }
}

Such operations have to be installed into an EcoSpace like this:

public static class OclInstaller
{
    /// <summary>
    /// InstallOclOperations
    /// </summary>
    /// <param name="ecoSpace">The EcoSpaceparam>
    public static void InstallOclOperations(EcoSpace ecoSpace)
    {
        if (ecoSpace != null)
        {
            var ocls = ecoSpace.GetEcoService<IOclService>();
            var eals = ecoSpace.GetEcoService<IActionLanguageService>();

            // Install all available operations in current assembly
            foreach (Type t in System.Reflection.Assembly.GetAssembly(typeof(OclInstaller)).GetTypes())
            {
                if (t.BaseType == typeof(OclOperationBase))
                {
                    var op = (OclOperationBase)Activator.CreateInstance(t);
                    eals.InstallOperation(op);

                    object[] attributes = t.GetCustomAttributes(typeof(EcoOclOperationAttribute), false);
                    if (attributes.Length == 1)
                    {
                        if ((attributes[0] as EcoOclOperationAttribute).IsQuery)
                        {
                            ocls.InstallOperation(op);
                        }
                    }
                    else
                    {
                        ocls.InstallOperation(op);
                    }
                }
            }
        }
        else
        {
            throw new NullReferenceException("Error in [InstallOclOperations]: EcoSpace is null.");
        }
    }
}

Call this installer in the constructor of the ecospace:

OclInstaller.InstallOclOperations(this);

It is amazing how easy it is with MDriven to add new custom OCL operations. As Hans tells, it is not possible to evaluate OCLs out of the box, but you could write you own evaluator. But please take a step back and take a proper archtitectural decision about the way you implement your function.

You can also add custom EcoServices but this is a competely different story.

Peter Buchmann
  • 157
  • 1
  • 11
1

There is no way to evaluate ocl/eal from within ocl/eal itself. It has been suggested but down voted due to security implications and the self-modifying-code-is-really-strange-argument.

The simple work-around in MDriven for Visual Studio is to add a Eval method on your superclass - and implement it in c# - and have that call ocl or eal service.

I guess you can have the Eval method return a Collection(SuperClass) or SuperClass if you want to act on the result

Hans Karlsen
  • 2,275
  • 1
  • 15
  • 15