Proper way to use an URCap as a dependency

I am facing an interesting issue that I think will help many future progarmmers if we are able to find a solutio together.

Imagine you created an URCap that does something very simple, let’s say turning on and off the correct sequence of digital outputs, let’s call this URCap A.

Now imagine that you created a more complex URCap which automates the creation of a process, and in that process you need to turn on and off the correct sequence of digital outputs, let’s call this URCap B.

It would be natural to think, as a programmer, that there is no need to duplicate the code of A, it is sufficient to insert A as a child node of B.

So far, this IS possible, by inserting URCap A as a dependency in the pom.xml file of B:

This way we can use A in B’s contribution

However, this does not let us use A as a child node YET, since A will need to be registered in the B’s Activator alongside B itself.
bundleContext.registerService(SwingProgramNodeService.class, new AService(), null);
bundleContext.registerService(SwingProgramNodeService.class, new BService(), null);

Everything will now work as desired, except… not quite…

Imagine now that a third URCap, called C, also depends on A, what will happen then?

If we use the same exact code for both there will be 2 entries of URCap A on the leftside of the program tab under tha available URCaps, and we don’t want that!

What if in the future URCap A will be a dependency of 20 different URCaps?
Are we going to keep 20 exact copies of A cluttering the tab?

I have found that with some clever workaround it is possible to automatically avoid to reinstall URCaps that are already registered to the bundle, and it is even possible to unregister them!

Sorry for the wall of text but it was all needed context, here is the problem:
An URCap that depends on another URCap MUST register the dependency in their own Activator, even if the dependency was already registered in the Bundle.

Skipping registration or unregistering an URCap because it was already registered by other URCaps does not work as intended.

In the previous example, if URCap C skips registering URCap A because it was already registered by URCap B what will happen is the following:

  • There will be no errors or warnings.
  • When looking at the URCaps tab we will see one entry for each URCap: A, B and C, exactly like we want.
  • When inserting URCap A and B there will be no problem, they will behave as expected.
  • But, when inserting C, it will be unable to create its own A childnode, since it didn’t register it itself.
  • Usually the returned error is something like:
    ERROR - Null child not allowed {thread: AWT-EventQueue-0 , loggerClass: com.ur.urcap.domain.program.TreeNodeImpl}
    com.ur.urcap.api.domain.program.structure.TreeStructureException: Null child not allowed

Because when trying to create a URCap child, if the operation fails it will return null, and trying to add null to the program tree is not allowed.

I am asking for someone to create an example where they correctly deal with this issue (@jbm maybe), in particular it would be extremely appreciated if you could convert the example here:

But instead of having the Activator registering both Services in the same file, splitting the 2 contributions in 2 standalone URCaps and then clearly showing that the parent one MUST depend on the child one.

Anyways, sorry again for the wall of text, if I get confirmation that what I want to do is currently impossible (having URCaps that depend on other URCaps which work even if it wasn’t their Activator to register the required URCap) I will create a similar post as a feature request.

Thanks for your time!