Skip to content

Commit

Permalink
The various contexts now allow for checking for the existence of a da…
Browse files Browse the repository at this point in the history
…ta manager without having to handle an exception. Refactored tests over retrieving data managers to be more robust. (#268)
  • Loading branch information
shawnhatch authored Oct 25, 2024
1 parent 81cf47b commit 92484b5
Show file tree
Hide file tree
Showing 7 changed files with 552 additions and 152 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -115,10 +115,36 @@ public boolean actorExists(final ActorId actorId) {
return simulation.actorExists(actorId);
}

/**
* Returns the data manager instance matching the class reference.
*
*
* @throws ContractException
*
* <ul>
* <li>{@linkplain NucleusError#NULL_DATA_MANAGER_CLASS}
* if the class reference is null</li>
* <li>{@linkplain NucleusError#AMBIGUOUS_DATA_MANAGER_CLASS}
* if there is more than one data manager instance
* matching the class reference</li>
* <li>{@linkplain NucleusError#UNKNOWN_DATA_MANAGER}
* if there are no data manager instances matching the
* class reference</li>
* </ul>
*
*/
public <T extends DataManager> T getDataManager(Class<T> dataManagerClass) {
return simulation.getDataManagerForActor(dataManagerClass);
}

/**
* Returns true if and only if there is exactly one data manager instance
* matching the given class reference. Null tolerant.
*/
public <T extends DataManager> boolean dataManagerExists(Class<T> dataManagerClass) {
return simulation.dataManagerExists(dataManagerClass);
}

public double getTime() {
return simulation.time;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -110,10 +110,10 @@ public void releaseObservationEvent(final Event event) {
}

/**
* Broadcasts the given event to a single actor. This is used
* for OBSERVATION events that are generated by the data managers. MUTATION
* events that are generated by the data managers as a proxy for actors and data
* managers should use releaseMutationEvent() instead.
* Broadcasts the given event to a single actor. This is used for OBSERVATION
* events that are generated by the data managers. MUTATION events that are
* generated by the data managers as a proxy for actors and data managers should
* use releaseMutationEvent() instead.
*
* @throws ContractException
* <ul>
Expand Down Expand Up @@ -198,10 +198,49 @@ public boolean actorExists(final ActorId actorId) {
return simulation.actorExists(actorId);
}

/**
* Returns the data manager instance matching the class reference.
*
*
* @throws ContractException
*
* <ul>
* <li>{@linkplain NucleusError#NULL_DATA_MANAGER_CLASS}
* if the class reference is null</li>
* <li>{@linkplain NucleusError#AMBIGUOUS_DATA_MANAGER_CLASS}
* if there is more than one data manager instance
* matching the class reference</li>
* <li>{@linkplain NucleusError#UNKNOWN_DATA_MANAGER}
* if there are no data manager instances matching the
* class reference</li>
* <li>{@linkplain NucleusError#DATA_MANAGER_ACCESS_VIOLATION}
* if the invoking data manager does not have access
* to the instance associated with the class
* reference. This happens where there is not a plugin
* dependency chain from the requestor to the
* requested if they are contained in different
* plugins. Within a plugin, access is granted for
* data manager types that were added by their plugin
* before the invoking instance.<i>
*
*
*
* </ul>
*
*/
public <T extends DataManager> T getDataManager(Class<T> dataManagerClass) {
return simulation.getDataManagerForDataManager(dataManagerId, dataManagerClass);
}

/**
* Returns true if and only if there is exactly one data manager instance
* matching the given class reference that is available to the data manager that
* is requesting the instance. Null tolerant.
*/
public <T extends DataManager> boolean dataManagerExists(Class<T> dataManagerClass) {
return simulation.dataManagerExistsForDataManager(dataManagerId, dataManagerClass);
}

public double getTime() {
return simulation.time;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,8 @@ protected ReportContext(Simulation simulation) {
*
* @throws ContractException
* <ul>
* <li>{@link NucleusError#NULL_PLAN_CONSUMER} if the consumer is
* null</li>
* <li>{@link NucleusError#NULL_PLAN_CONSUMER} if the
* consumer is null</li>
* <li>{@link NucleusError#PAST_PLANNING_TIME} if the
* plan is scheduled for a time in the past *</li>
* <li>{@link NucleusError#PLANNING_QUEUE_CLOSED} if
Expand Down Expand Up @@ -146,6 +146,14 @@ public <T extends DataManager> T getDataManager(Class<T> dataManagerClass) {
return simulation.getDataManagerForActor(dataManagerClass);
}

/**
* Returns true if and only if there is exactly one data manager instance
* matching the given class reference. Null tolerant.
*/
public <T extends DataManager> boolean dataManagerExists(Class<T> dataManagerClass) {
return simulation.dataManagerExists(dataManagerClass);
}

public double getTime() {
return simulation.time;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1275,6 +1275,40 @@ protected void removeActor(final ActorId actorId) {
containsDeletedActors = true;
}

protected <T extends DataManager> boolean dataManagerExists(Class<T> dataManagerClass) {
boolean result = false;
if (dataManagerClass != null) {

DataManager dataManager = workingClassToDataManagerMap.get(dataManagerClass);
/*
* If the working map does not contain the data manager, try to find a single
* match from the base map that was collected from the plugins.
*
* If two or more matches are found, then throw an exception.
*
* If exactly one match is found, update the working map.
*
* If no matches are found, nothing is done, but we are vulnerable to somewhat
* slower performance if the data manager is sought repeatedly.
*/
if (dataManager == null) {
List<Class<?>> candidates = new ArrayList<>();
for (Class<?> c : baseClassToDataManagerMap.keySet()) {
if (dataManagerClass.isAssignableFrom(c)) {
candidates.add(c);
}
}

if (candidates.size() == 1) {
dataManager = baseClassToDataManagerMap.get(candidates.get(0));
workingClassToDataManagerMap.put(dataManagerClass, dataManager);
}
}
result = dataManager != null;
}
return result;
}

@SuppressWarnings("unchecked")
protected <T extends DataManager> T getDataManagerForActor(Class<T> dataManagerClass) {

Expand Down Expand Up @@ -1315,6 +1349,58 @@ protected <T extends DataManager> T getDataManagerForActor(Class<T> dataManagerC
}
return (T) dataManager;
}


protected <T extends DataManager> boolean dataManagerExistsForDataManager(DataManagerId dataManagerId,
Class<T> dataManagerClass) {

if (dataManagerClass == null) {
return false;
}

DataManager dataManager = workingClassToDataManagerMap.get(dataManagerClass);
/*
* If the working map does not contain the data manager, try to find a single
* match from the base map that was collected from the plugins.
*
* If two or more matches are found, then throw an exception.
*
* If exactly one match is found, update the working map.
*
* If no matches are found, nothing is done, but we are vulnerable to somewhat
* slower performance if the data manager is sought repeatedly.
*/
if (dataManager == null) {
List<Class<?>> candidates = new ArrayList<>();
for (Class<?> c : baseClassToDataManagerMap.keySet()) {
if (dataManagerClass.isAssignableFrom(c)) {
candidates.add(c);
}
}
if (candidates.size() > 1) {
return false;
}
if (candidates.size() == 1) {
dataManager = baseClassToDataManagerMap.get(candidates.get(0));
workingClassToDataManagerMap.put(dataManagerClass, dataManager);
}
}

if (dataManager == null) {
return false;
}

int requestorId = dataManagerId.getValue();
DataManagerId dataManagerId2 = dataManagerToDataManagerIdMap.get(dataManager);
int requesteeId = dataManagerId2.getValue();

boolean accessGranted = dataManagerAccessPermissions[requestorId][requesteeId];

if (!accessGranted) {
return false;
}
return true;
}

@SuppressWarnings("unchecked")
protected <T extends DataManager> T getDataManagerForDataManager(DataManagerId dataManagerId,
Expand Down Expand Up @@ -1492,10 +1578,10 @@ protected boolean subscribersExistForEvent(Class<? extends Event> eventClass) {
}

/*
* Recursively processes the event through the filter node to the given actor. Events should be
* processed through the root filter node. Each node's consumers have each such
* consumer scheduled onto the actor queue for delayed execution of the
* consumer.
* Recursively processes the event through the filter node to the given actor.
* Events should be processed through the root filter node. Each node's
* consumers have each such consumer scheduled onto the actor queue for delayed
* execution of the consumer.
*/
private void broadcastEventToFilterNodeAndActor(final Event event, FilterNode filterNode, ActorId actorId) {
// determine the value of the function for the given event
Expand Down
Loading

0 comments on commit 92484b5

Please sign in to comment.