Create PhysicalComponent with a CapellaElement Node

Hi all,

I am using a new plugin that tries to simulate electrical components. In essence what it does is to add a node (WNode) to a PhysicalComponent. You can see it here:

The first thing I did was to map the WNode element as a CapellaElement in Capella.py:

I can list and rename WNode elements (that’s good?) however I can’t in any way add this property to a physicalComponent like in the first picture through python, the code I use is:

model = CapellaModel()
model.open(aird_path)

# gets the SystemEngineering
se = model.get_system_engineering()
# get the PhysicalComponentPkg
pc_pkg = se.get_physical_architecture().get_physical_system()

# start a transaction to modify the Capella model
model.start_transaction()

try:
    pc = NodePC()
    pc.set_name("Comp1") 
    pc_pkg.get_owned_physical_components().add(pc)
    
    WN = WNode()    
    WN.set_name("FirstWNode") 
    
    pc.get_java_object().getOwnedPhysicalComponents().add(WN.get_java_object())#NOT WORKING LINE
    org.polarsys.capella.core.model.helpers.CapellaElementExt.creationService(pp.get_java_object())
        
except:
    # if something went wrong we rollback the transaction
    model.rollback_transaction()
    raise
else:
    # if everything is ok we commit the transaction
    model.commit_transaction()

# save the Capella model
model.save()

I get the following error:

java.lang.ArrayStoreException
	at org.eclipse.emf.ecore.util.DelegatingEcoreEList.validate(DelegatingEcoreEList.java:147)
	at org.eclipse.emf.common.util.DelegatingEList.addUnique(DelegatingEList.java:334)
	at org.eclipse.emf.common.notify.impl.DelegatingNotifyingListImpl.doAddUnique(DelegatingNotifyingListImpl.java:379)
	at org.eclipse.emf.common.notify.impl.DelegatingNotifyingListImpl.addUnique(DelegatingNotifyingListImpl.java:275)
	at org.eclipse.emf.common.util.AbstractEList.add(AbstractEList.java:304)
	at jdk.internal.reflect.GeneratedMethodAccessor177.invoke(Unknown Source)
	at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.base/java.lang.reflect.Method.invoke(Method.java:564)
	at py4j.reflection.MethodInvoker.invoke(MethodInvoker.java:244)
	at py4j.reflection.ReflectionEngine.invoke(ReflectionEngine.java:357)
	at py4j.Gateway.invoke(Gateway.java:282)
	at py4j.commands.AbstractCommand.invokeMethod(AbstractCommand.java:132)
	at py4j.commands.CallCommand.execute(CallCommand.java:79)
	at py4j.ClientServerConnection.sendCommand(ClientServerConnection.java:244)
	at py4j.CallbackClient.sendCommand(CallbackClient.java:384)
	at py4j.CallbackClient.sendCommand(CallbackClient.java:356)
	at py4j.reflection.PythonProxyHandler.invoke(PythonProxyHandler.java:106)
	at com.sun.proxy.$Proxy71.executeScript(Unknown Source)
	at org.eclipse.ease.lang.python.py4j.internal.Py4jScriptEngine.internalExecute(Py4jScriptEngine.java:240)
	at org.eclipse.ease.lang.python.py4j.internal.Py4jScriptEngine.execute(Py4jScriptEngine.java:227)
	at org.eclipse.ease.AbstractScriptEngine.inject(AbstractScriptEngine.java:189)
	at org.eclipse.ease.AbstractScriptEngine.run(AbstractScriptEngine.java:242)
	at org.eclipse.core.internal.jobs.Worker.run(Worker.java:63)

I have tried to use the sirius interpreter to find the right method (.add) but I am completely unable. Does anyone know what could be happening? Thanks in advance for your time and help.

You are doing great with your WNode Python API. To add an element to your NodePC you will need to use the ownedExtensions EReference but you will have to use the Java API:

pc.get_java_object().getOwnedExtensions().add(WN.get_java_object())

From what I understand WNode comes from a Capella addon. There is an Acceleo 4 generator that take an Ecore model and generate a Python4Capella API.

The generator is under development as well as Acceleo 4, but if you want to give it a try:

The launch configuration should look like this (change the Ecore model and output path):

1 Like

Thanks you a lot Yvan! I’m trying to follow all the procedure but I’m unable to find an Ecore file, what do you mean by that exactly? An internal wiring plugin file?

If you don’t have the source of your addon, the .ecore file will be in one of the plugins. If it has been generated with the Capella studio, it should be in the plugin with the shortest name (base name) and in a models folder. You can unpack the jar file (zip format) and get the ecore file for instance. You might also need any other metamodels dependencies (other .ecore files).

As an example:

You can find plugins in the update site you used to install this addon or in the plugins or droppins folder in your Capella installation.

1 Like

Hi thanks a lot for your detailed response. I cannot open the requirements addon link, can you send it again? Thanks!

It’s just a link to the source code. But in short if you wanted to get the .ecore file for the requirement addon you would need to:

  • find the org.polarsys.capella.vp.requirements_..jar (for instance org.polarsys.capella.vp.requirements_0.13.1.202303011400.jar) file:
    • in the udpate site you used to install the requirement addon
    • in the plugins folder of your Capella installation
    • in the droppings folder of your Capella installation
  • extract this jar with your favorite zip tool
  • in the models folder find the .ecore file

In the Ecore file you should find the WNode EClass if it can help you identify the file/plugin. If your addon has been developed by Obeo, let me know I would be able to generate the code for you.

1 Like

Thanks a lot for your fast response Yvan! I think I did manually all the python APIS I needed but I have a big problem that I want to consult you:

Aside from WNode (for Node PC) I have the equivalent WPort (for physical port). That WPort has wiring properties such as the signal type. I can have the signal type with the get, I cannot make a set because the WSignalType (input of the set) comes from another .java class that is not an Eclass, so I cannot make an python API for that. Is there any way I can do it?

I tried to extract the WSignalType property from other component (which is good, if I am not able to create that property I can get it from other spare component) but at the time I try to set that property into my element of interest I get this super strange error:

org.eclipse.swt.SWTException: Widget is disposed
	at org.eclipse.swt.SWT.error(SWT.java:4723)
	at org.eclipse.swt.SWT.error(SWT.java:4638)
	at org.eclipse.swt.SWT.error(SWT.java:4609)
	at org.eclipse.swt.widgets.Widget.error(Widget.java:432)
	at org.eclipse.swt.widgets.Widget.checkWidget(Widget.java:351)
	at org.eclipse.swt.widgets.Control.setVisible(Control.java:3914)
	at com.thalesgroup.vpd.wiring.ui.fields.WA664BandWidthEnumField_semanticKindGroup.setVisibleContent(WA664BandWidthEnumField_semanticKindGroup.java:97)
	at com.thalesgroup.vpd.wiring.ui.fields.WA664BandWidthEnumField_semanticKindGroup.refreshA664BandWidth(WA664BandWidthEnumField_semanticKindGroup.java:70)
	at com.thalesgroup.vpd.wiring.ui.sections.Wiring_WPort_Wiring_WPort_Section.notifyChangedSignalType(Wiring_WPort_Wiring_WPort_Section.java:547)
	at com.thalesgroup.vpd.wiring.ui.sections.Wiring_WPort_Wiring_WPort_Section.notifyChanged(Wiring_WPort_Wiring_WPort_Section.java:484)
	at org.eclipse.emf.common.notify.impl.BasicNotifierImpl.eNotify(BasicNotifierImpl.java:424)
	at org.eclipse.emf.ecore.impl.EStructuralFeatureImpl$InternalSettingDelegateSingleData.dynamicUnset(EStructuralFeatureImpl.java:2281)
	at org.eclipse.emf.ecore.impl.BasicEObjectImpl.eDynamicUnset(BasicEObjectImpl.java:1253)
	at org.eclipse.emf.ecore.impl.BasicEObjectImpl.eUnset(BasicEObjectImpl.java:1227)
	at org.polarsys.kitalpha.emde.model.impl.ExtensibleElementImpl.eUnset(ExtensibleElementImpl.java:124)
	at org.polarsys.capella.common.data.modellingcore.impl.ModelElementImpl.eUnset(ModelElementImpl.java:348)
	at org.polarsys.capella.common.data.modellingcore.impl.AbstractNamedElementImpl.eUnset(AbstractNamedElementImpl.java:131)
	at org.polarsys.capella.core.data.capellacore.impl.NamedElementImpl.eUnset(NamedElementImpl.java:745)
	at org.eclipse.emf.ecore.impl.BasicEObjectImpl.eUnset(BasicEObjectImpl.java:1197)
	at org.eclipse.emf.ecore.change.impl.FeatureChangeImpl.process(FeatureChangeImpl.java:544)
	at org.eclipse.emf.ecore.change.impl.FeatureChangeImpl.apply(FeatureChangeImpl.java:518)
	at org.eclipse.emf.ecore.change.impl.FeatureChangeImpl.apply(FeatureChangeImpl.java:493)
	at org.eclipse.emf.ecore.change.impl.ChangeDescriptionImpl.apply(ChangeDescriptionImpl.java:301)
	at org.eclipse.emf.transaction.util.CompositeChangeDescription.apply(CompositeChangeDescription.java:135)
	at org.eclipse.emf.transaction.impl.TransactionImpl.doRollback(TransactionImpl.java:570)
	at org.eclipse.emf.transaction.impl.TransactionImpl.rollback(TransactionImpl.java:547)
	at org.eclipse.python4capella.modules.SiriusModule.rollbackTransaction(SiriusModule.java:490)
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.base/java.lang.reflect.Method.invoke(Method.java:564)
	at py4j.reflection.MethodInvoker.invoke(MethodInvoker.java:244)
	at py4j.reflection.ReflectionEngine.invoke(ReflectionEngine.java:357)
	at py4j.Gateway.invoke(Gateway.java:282)
	at py4j.commands.AbstractCommand.invokeMethod(AbstractCommand.java:132)
	at py4j.commands.CallCommand.execute(CallCommand.java:79)
	at py4j.ClientServerConnection.sendCommand(ClientServerConnection.java:244)
	at py4j.CallbackClient.sendCommand(CallbackClient.java:384)
	at py4j.CallbackClient.sendCommand(CallbackClient.java:356)
	at py4j.reflection.PythonProxyHandler.invoke(PythonProxyHandler.java:106)
	at com.sun.proxy.$Proxy71.executeScript(Unknown Source)
	at org.eclipse.ease.lang.python.py4j.internal.Py4jScriptEngine.internalExecute(Py4jScriptEngine.java:240)
	at org.eclipse.ease.lang.python.py4j.internal.Py4jScriptEngine.execute(Py4jScriptEngine.java:227)
	at org.eclipse.ease.AbstractScriptEngine.inject(AbstractScriptEngine.java:189)
	at org.eclipse.ease.AbstractScriptEngine.run(AbstractScriptEngine.java:242)
	at org.eclipse.core.internal.jobs.Worker.run(Worker.java:63)

Did you saw this error in the past? Any clue of how can I solve it?

Thanks a lot for your time and help, good weekend

You can call Java code from your Python4Capella script. If it’s a simple call to a constructor you can use something like:

mySignalType = qualified.name.to.WSignalType()

or

mySignalType = qualified.name.to.WSignalType('Type1')

Depending of the signature of the constructor for the class WSignalType.

You can also directly call enums in the same way. If you need more than a few call you can encapsulate the Java code in a Python method to reuse it or you can create an EASE module (this defeats the goal of Python4Capella a bit). Some APIs from Python4Capelle use such modules with a Java class with annotated methods and registered with an extension point.

This exception is not a good news. It looks like the some code is called (when the wiring port is set ?) that depend on some UI (tries to make a widget visible) that is not present since you do this programmatically. This code is specific to your addon so maybe you can check with the provider of this addon for more details and maybe a fix.

1 Like

Thanks again for your fast and accurate response, and forgive my insistence but it’s very relevant for my current job. From that:

I get an error because qualified is not defined in my script, am I missing something? After looking more carefully the problematic constructor is:

public enum WSignalTypeEnum implements Enumerator {
        Code 
} // WSignalTypeEnum

So yes, it’s indeed an enum. Do you have an example of how to call this method directly from P4C? Since its an enum I am not able to create an API for that.

Thanks a lot again for your time and help, sorry for the insistance, I wish you a good weekend.

1 Like

This error comes from PyDev not knowing which symbols will be available at runtime (symbols from Java). You can change the configuration of PyDev to remove this error.

Your WSignalTypeEnum is an EEnum (from EMF), you can get the value using the following code (adapt the nsURI, enum, and enum literal names):

myType = get_enum_literal("http://www.polarsys.org/capella/common/re/" + capella_version(), "CatalogElementKind", "REC")

then you can use myType to set the type of your element.

1 Like

Thanks a lot again for another response Yvan, forgive again my insistence. I cannot fix the qualify error, even with the error avoiding tip you gave me a few weeks ago.

On the other side, I understand that you want me to put something like this in my current script (not in capella.py):

myType = get_enum_literal("http adress" + capella_version(), "???", "WSignalTypeEnum")
myType.get_java_object().setSignalType(Whatever)

Thats a way to call Enums directly from my script isn’t it? My problem is that I am not capable of finding the proper enum and enum literal names. I don’t know which one of them I am putting wrong because I get the “java.lang.NullPointerException”. I understand that from the code I sent you the field enum literal names (the third) is “WSignalTypeEnum”, the name of the .java public enum, but how I can get the second? I tested several but I cannot find the good one.

Thank you again, as always your help is very appreciated. Have a good week.

1 Like

For the qualified name error make sure you selected the undefined tab:

For the type the code should look more like:

myTypedElement = ...
myType = get_enum_literal("http adress" + capella_version(), "WSignalTypeEnum", "TYPE1")
myTypedElement.get_java_object().setSignalType(myType)

And yes, you can put this code in your script, not sure it make sens to make an API on your side. To get the nsURI and enum literal name, you can use the ecore file or open the Java code of the class WSignalTypeEnum next to it you should see Package.class, you will find the nsURI in this class. The enum literal name is in the WSignalTypeEnum class. To access this code from your workspace you can import the plugin in your workspace:

  • enable development capabilities in your Capella
  • import the plugin
    • right click in the project explorer
    • select import menu
    • select plug-in development
    • select plug-in and fragment
    • then click next and select your plugin, it should have the same name as the prefix of the qualifier name of your class WSignalTypeEnum
1 Like

Thanks again Yvan. The qualified thing returns the following error even following all the steps you showed me carefully:

org.eclipse.ease.ScriptExecutionException: Traceback (most recent call last):
  File "workspace://Python4Capella/TMT-P4C-AMJ-CODE/LIB_TEST2.py", line 35, in <module>
    try:
NameError: name 'qualified' is not defined

Maybe something is required on the script? Aside from the preference modif.

Sadly I don’t have any .class for reference but according to .ecore file I have that the value of properties of WSignalTypeEnum is:
image
So I guess I have the first and second field, but I suspect that the third field “TYPE1” is where the problem is… I’m unable to find the literal name in the ecore file following strictly the procedure you showed me, where I can find it instead?

Thanks you again, have a nice afternoon.

Did you keep the line qualified.name.to.WSignalType. You should not need it an use get_enum_literal() instead. And if you needed this line you need to replace qualified.name.toby the real qualified name (org…, com…).

For the enum literal name you can replace TYPE1 by PWR_5VAC or other values at the same level in the Ecore model.

1 Like

Thank you very much Yvan, this last detailed response just worked perfectly for me. Thanks a lot for all your help.

1 Like