I have run into the following situation a couple of times and I cannot find a fully satisfying solution:
I am developing a Java application using OSGi and, following OSGi's best practices, it is highly modularized. Here's an extract of some of my plugins and classes in them:
- com.example.core.db.manager (plugin)
|- com.example.core.db.manager (package)
|- DatabaseManager (interface)
- com.example.core.business.objectmanager (plugin)
|- com.example.core.business.objectmanager (package)
|- BusinessObjectManager (interface)
- com.example.some.businessobjectmanager.consumer (plugin)
|- com.example.some.businessobjectmanager.consumer (package)
|- SomeBusinessObjectManagerConsumer (interface)
(obviously this is not the real name, but the name is irrelevant)
Where
DatabaseManager
is a low-level construct that interacts directly with the database.BusinessObjectManager
is a high-level construct that acts (among other things) as a sort of adapter for theDatabaseManager
.SomeBusinessObjectManagerConsumer
consumesBusinessObjectManager
and should not know about the underlying database, not even that there is a database. It should not know about theDatabaseManager
; rather, it should interact only with theBusinessObjectManager
.
So far so good. But now SomeBusinessObjectManagerConsumer
needs to update some edges between entities in the database (I use a graph database, meaning my entities (what would normally be rows in a table) are nodes, and the relationships between them are edges). As explained before SomeBusinessObjectManagerConsumer
doesn't know anything about the database, but it knows there are some "business objects" (nodes) and that there are links between some of them (edges).
In BusinessObjectManager
, I create a method replaceLinks
as follows...
UpdatedLinks replaceLinks(BusinessObjectUID from, Set<BusinessObjectUID> to);
...which is supposed to make sure that, by the time it returns, the from
business object will only be linked to the to
objects, possibly removing previous links and adding new ones. I would like to know about these removals and additions. I create an interface UpdatedLinks
in plugin com.example.core.business.objectmanager
:
public interface UpdatedLinks {
Set<BusinessObjectUID> getRemovedLinks();
Set<BusinessObjectUID> getAddedLinks();
}
But the BusinessObjectManager
is not really the one who is going to perform this link replacement and put together the UpdatedLinks
return object. Instead, it delegates this to DatabaseManager
. So I create an equivalent method in DatabaseManager
, and BusinessObjectManager
will simply invoke this method.
The problem now is where to place the interface UpdatedLinks
: it is needed by DatabaseManager
, BusinessObjectManager
and SomeBusinessObjectManagerConsumer
, but the dependencies between these classes (and their corresponding plugins) goes in this direction:
SomeBusinessObjectManagerConsumer ---depends-on---> BusinessObjectManager ---depends-on---> DatabaseManager
So:
- I cannot put
UpdatedLinks
inBusinessObjectManager
's plugin because then it is not visible forDatabaseManager
. - I cannot put it in
DatabaseManager
's plugin because then it is not visible forSomeBusinessObjectManagerConsumer
(remember thatSomeBusinessObjectManagerConsumer
doesn't know anything aboutDatabaseManager
; because of modularization in OSGi, it can only have access toDatabaseManager
if I declare an explicit dependency on it, which I don't want to do). - It is too specific to put it in some kind of "utilities" plugin.
- I do not currently have any plugin where it makes sense to put this interface and that would make it available to all the dependent plugins.
Basically, I would have to create a new plugin just for this interface and I cannot even find any meaningful name for that plugin, considering who is going to depend on it. (But mainly, I resist the idea of creating a plugin just for this interface, which exists just as a means to deliver the results of the replaceLinks
method).
I have encountered this situation several times (especially lately using OSGi, because of the modularization) and I can never find a fully satisfying solution. What would/do you do in such a case?
"Meta" disclaimers:
- The title could be better; I just can't come up with a better one. Feel free to change it.
- I'm not sure whether stackoverflow is the right StackExchange community for this question so please feel free to recommend others that may be more appropriate. I couldn't find a better one.
- I tried to explain in detail so that you can picture the situation. I hope I didn't overdo it ;)