Hi!
I’m trying to automatically create the skeleton of a logical architecture using python4capella.
So far I managed to create logical components, subcomponents, ports, and component exchanges. Now I wan’t to allocate Exchange Items to each corresponding Component Exchange. I created the exchange items automatically in the interface package, but I don’t know how to link them to a component exchange.
Does anybody know how to allocate an exchange item to a component exchange with python4capella ?
Thanks,
V.
I think you can only allocate ExchangeItem to LogicalFunction in the LogicalArchitexture…
If you have a way to do what you need to do via the Capella UI, you can use the UI to make the changes and then compare .capella model before and after. This will give you the type of element to instantiate and also the name of the references and attribute to set.
For allocating to a LogicalFunction the following should work:
my_exchange_item = ExchangeItem()
my_interface_pkg = InterfacePkg() # get the InterfacePkg from your project LogicalArchitecture
my_interface_pkg.get_owned_exchange_items().add(my_exchange_item)
org.polarsys.capella.core.model.helpers.CapellaElementExt.creationService(my_exchange_item.get_java_object())
my_logical_function = LogicalFunction()
my_functional_exchange = FunctionalExchange()
my_logical_function.get_owned_functional_exchanges().add(my_functional_exchange)
org.polarsys.capella.core.model.helpers.CapellaElementExt.creationService(my_functional_exchange.get_java_object())
my_functional_exchange.get_exchanged_items().add(my_exchange_item)
You will need to connect the FunctionalExchange if you creates it via your script.
After doing what you suggested (checking the .capella xml file), I found out that components exchanges have a method called get_convoyed_informations(), which returns a list of ExchangeItems
Thank You!
2 Likes
I am trying to clear the list returned by get_convoyed_informations(), but i get a java.lang.ArrayIndexOutOfBoundsException when i do ce.get_convoyed_informations().clear()
What am I doing wrong ?
This should call the Java List.clear() method. I don’t think the Java method would throw this kind of exception.
You can call the Java method directly but it probably won’t change anything:
ce.get_convoyed_informations().get_java_object().clear()
Are you sure the exception is thrown on this line ? Because clearing the list and then accessing an element inside will throw an java.lang.ArrayIndexOutOfBoundsException…
I tried surrounding the statement with prints. It seems the problem is here
print("before")
print(ce)
ce.get_convoyed_informations().clear()
print("after")
gives :
before
<__main__.ComponentExchange object at 0x000001B7ECCA5C48>
java.lang.ArrayIndexOutOfBoundsException
OK… do you have the full Java stack trace ? I don’t think accessing the List triggers more Java computation but maybe something in the stack.
I tried the same code on a new ComponentExchange and I get an NPE:
java.lang.NullPointerException: Cannot load from object array because "this.data" is null
at org.eclipse.emf.common.util.BasicEList.remove(BasicEList.java:604)
at org.eclipse.emf.common.notify.impl.NotifyingListImpl.doRemove(NotifyingListImpl.java:756)
at org.eclipse.emf.common.notify.impl.NotifyingListImpl.remove(NotifyingListImpl.java:737)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:568)
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 jdk.proxy15/jdk.proxy15.$Proxy40.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)
Maybe you can tray to remove elements one by one as a workaround. I wonder if the reflective Java call skip some initialization code… But at the same time nothing would work in that case.
Removing items one by one using the following code
for x in ce.get_convoyed_informations():
ce.get_convoyed_informations().remove(x)
results in
java.util.ConcurrentModificationException
at org.eclipse.emf.common.util.AbstractEList$EIterator.checkModCount(AbstractEList.java:751)
at org.eclipse.emf.common.util.AbstractEList$EIterator.doNext(AbstractEList.java:699)
at org.eclipse.emf.common.util.AbstractEList$EIterator.next(AbstractEList.java:685)
at org.eclipse.python4capella.modules.JavaModule.iteratorNext(JavaModule.java:46)
at jdk.internal.reflect.GeneratedMethodAccessor168.invoke(Unknown Source)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:568)
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 jdk.proxy11/jdk.proxy11.$Proxy24.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)
you can’t modify a list you are accessing. You can warp the list into an other list to avoid this exception (in Java, but it can be done in Python also):
for value in java.util.ArrayList((ce.get_convoyed_informations().get_java_object())):
ce.get_convoyed_informations().get_java_object().remove(value)
The following code works:
for value in list(ce.get_convoyed_informations()):
ce.get_convoyed_informations().remove(value)
Thanks!
1 Like
It seems the problem is still here: I have the following code, that builds a map associating names to component exchanges.
At the same time it should delete/RAZ the allocated functionnal exchanges :
def build_component_exchange_map(root):
result = {}
for component_a in root.get_owned_logical_components():
result.update(build_component_exchange_map(component_a))
for port in root.get_contained_component_ports():
for component_exchange in port.get_component_exchanges():
# reset functional exchanges allocation
for x in list(component_exchange.get_allocated_functional_exchanges()):
component_exchange.get_allocated_functional_exchanges().remove(x)
print("from",component_exchange.get_name(),"deleting", x.get_id(), len(component_exchange.get_allocated_functional_exchanges()))
result[component_exchange.get_name()] = component_exchange
return result
but I get the following (partial) output (the length of the list doesn’t change):
from XXX-YYY deleting 9be48cdc-2024-4f3b-b58b-f28eace49f01 4
from XXX-YYY deleting e806d60c-f25c-4693-9388-06bcd5b2abfe 4
from XXX-YYY deleting 13f84e81-f96a-4f07-b442-c5d8900bae3c 4
from XXX-YYY deleting bc299797-5279-4689-a840-117b662d236d 4
In the documentation it says that “allocatedFunctionalExchanges” is both a setter and getter… how do I access the “setter” version ?
The following seems to be working:
for x in list(component_exchange.get_owned_component_exchange_functional_exchange_allocations()):
component_exchange.get_owned_component_exchange_functional_exchange_allocations().remove(x)
1 Like