diff --git a/pass-grant-loader/pass-grant-data/src/main/java/org/eclipse/pass/support/grant/data/DefaultPassUpdater.java b/pass-grant-loader/pass-grant-data/src/main/java/org/eclipse/pass/support/grant/data/AbstractDefaultPassUpdater.java similarity index 86% rename from pass-grant-loader/pass-grant-data/src/main/java/org/eclipse/pass/support/grant/data/DefaultPassUpdater.java rename to pass-grant-loader/pass-grant-data/src/main/java/org/eclipse/pass/support/grant/data/AbstractDefaultPassUpdater.java index d7b5e5ed..06b2eee4 100644 --- a/pass-grant-loader/pass-grant-data/src/main/java/org/eclipse/pass/support/grant/data/DefaultPassUpdater.java +++ b/pass-grant-loader/pass-grant-data/src/main/java/org/eclipse/pass/support/grant/data/AbstractDefaultPassUpdater.java @@ -31,18 +31,13 @@ import static org.eclipse.pass.support.grant.data.CoeusFieldNames.C_PRIMARY_FUNDER_NAME; import static org.eclipse.pass.support.grant.data.CoeusFieldNames.C_PRIMARY_FUNDER_POLICY; import static org.eclipse.pass.support.grant.data.CoeusFieldNames.C_UPDATE_TIMESTAMP; -import static org.eclipse.pass.support.grant.data.CoeusFieldNames.C_USER_EMAIL; import static org.eclipse.pass.support.grant.data.CoeusFieldNames.C_USER_EMPLOYEE_ID; -import static org.eclipse.pass.support.grant.data.CoeusFieldNames.C_USER_FIRST_NAME; -import static org.eclipse.pass.support.grant.data.CoeusFieldNames.C_USER_LAST_NAME; -import static org.eclipse.pass.support.grant.data.CoeusFieldNames.C_USER_MIDDLE_NAME; import static org.eclipse.pass.support.grant.data.DateTimeUtil.createZonedDateTime; import java.io.IOException; import java.time.ZonedDateTime; import java.util.Collection; import java.util.HashMap; -import java.util.ListIterator; import java.util.Map; import java.util.Objects; @@ -68,11 +63,10 @@ * @author jrm@jhu.edu */ -public class DefaultPassUpdater implements PassUpdater { - private static final Logger LOG = LoggerFactory.getLogger(DefaultPassUpdater.class); +abstract class AbstractDefaultPassUpdater implements PassUpdater { + private static final Logger LOG = LoggerFactory.getLogger(AbstractDefaultPassUpdater.class); private static final String GRANT_ID_TYPE = "grant"; - private static final String EMPLOYEE_ID_TYPE = "employeeid"; private static final String FUNDER_ID_TYPE = "funder"; private String domain = "default.domain"; @@ -80,7 +74,6 @@ public class DefaultPassUpdater implements PassUpdater { private final PassClient passClient; private final PassUpdateStatistics statistics = new PassUpdateStatistics(); - private final PassEntityUtil passEntityUtil; private final Map grantResultMap = new HashMap<>(); @@ -92,17 +85,10 @@ public class DefaultPassUpdater implements PassUpdater { private String mode; - DefaultPassUpdater(PassEntityUtil passEntityUtil) { - this.passEntityUtil = passEntityUtil; + AbstractDefaultPassUpdater() { this.passClient = PassClient.newInstance(); } - //used in unit testing for injecting a mock client - DefaultPassUpdater(PassEntityUtil passEntityUtil, PassClient passClient) { - this.passEntityUtil = passEntityUtil; - this.passClient = passClient; - } - public void updatePass(Collection> results, String mode) { this.mode = mode; userMap.clear(); @@ -110,20 +96,50 @@ public void updatePass(Collection> results, String mode) { statistics.reset(); statistics.setType(mode); switch (mode) { - case "grant": - updateGrants(results); - break; - case "user": - updateUsers(results); - break; - case "funder": - updateFunders(results); - break; - default: - break; + case "grant" -> updateGrants(results); + case "user" -> updateUsers(results); + case "funder" -> updateFunders(results); + default -> { + } } } + void setDomain(String domain) { + this.domain = domain; + } + + /** + * This method provides the latest timestamp of all records processed. After processing, this timestamp + * will be used to be tha base timestamp for the next run of the app + * + * @return the latest update timestamp string + */ + public String getLatestUpdate() { + return this.latestUpdateString; + } + + /** + * This returns the final statistics of the processing of the Grant or User Set + * + * @return the report + */ + public String getReport() { + return statistics.getReport(); + } + + /** + * This returns the final statistics Object - useful in testing + * + * @return the statistics object + */ + public PassUpdateStatistics getStatistics() { + return statistics; + } + + public Map getGrantResultMap() { + return grantResultMap; + } + /** * Build a Collection of Grants from a ResultSet, then update the grants in Pass * Because we need to make sure we catch any updates to fields referenced by URIs, we construct @@ -272,7 +288,7 @@ private void updateGrants(Collection> results) { ? grantUpdateString : DateTimeUtil.returnLaterUpdate(grantUpdateString, latestUpdateString); } - } catch (IOException | GrantDataException e) { + } catch (Exception e) { LOG.error("Error building Grant Row with localKey: " + grantLocalKey, e); } } @@ -324,7 +340,7 @@ private void updateUsers(Collection> results) { ? userUpdateString : DateTimeUtil.returnLaterUpdate(userUpdateString, latestUpdateString); } - } catch (IOException | GrantDataException e) { + } catch (Exception e) { LOG.error("Error processing User: " + rowUser, e); } } @@ -369,24 +385,6 @@ private void updateFunders(Collection> results) { statistics.setReport(results.size(), funderProcessedCounter); } - User buildUser(Map rowMap) { - User user = new User(); - user.setFirstName(rowMap.get(C_USER_FIRST_NAME)); - user.setMiddleName(rowMap.getOrDefault(C_USER_MIDDLE_NAME, null)); - user.setLastName(rowMap.get(C_USER_LAST_NAME)); - user.setDisplayName(rowMap.get(C_USER_FIRST_NAME) + " " + rowMap.get(C_USER_LAST_NAME)); - user.setEmail(rowMap.get(C_USER_EMAIL)); - String employeeId = rowMap.get(C_USER_EMPLOYEE_ID); - //Build the List of locatorIds - put the most reliable ids first - if (employeeId != null) { - String localKey = GrantDataUtils.buildLocalKey(domain, EMPLOYEE_ID_TYPE, employeeId); - user.getLocatorIds().add(localKey); - } - user.getRoles().add(UserRole.SUBMITTER); - LOG.debug("Built user with employee ID {}", employeeId); - return user; - } - /** * this method gets called on a grant mode process if the primary funder is different from direct, and also * any time the updater is called in funder mode @@ -443,7 +441,7 @@ private Funder updateFunderInPass(Funder systemFunder) throws IOException, Grant if (!result.getObjects().isEmpty()) { Funder storedFunder = getSingleObject(result, fullLocalKey); - Funder updatedFunder = passEntityUtil.update(systemFunder, storedFunder); + Funder updatedFunder = updateFunderIfNeeded(systemFunder, storedFunder); if (Objects.nonNull(updatedFunder)) { //need to update passClient.updateObject(updatedFunder); statistics.addFundersUpdated(); @@ -466,26 +464,15 @@ private Funder updateFunderInPass(Funder systemFunder) throws IOException, Grant * @param systemUser the new User object populated from COEUS * @return the URI for the resource representing the updated User in Pass */ - private User updateUserInPass(User systemUser) throws IOException, GrantDataException { - //we first check to see if the user is known by the Hopkins ID. If not, we check the employee ID. - //last attempt is the JHED ID. this order is specified by the order of the List as constructed on updatedUser - User passUser = null; - ListIterator idIterator = systemUser.getLocatorIds().listIterator(); - - while (passUser == null && idIterator.hasNext()) { - String id = String.valueOf(idIterator.next()); - if (id != null) { - PassClientSelector selector = new PassClientSelector<>(User.class); - selector.setFilter(RSQL.hasMember("locatorIds", id)); - PassClientResult result = passClient.selectObjects(selector); - passUser = result.getObjects().isEmpty() - ? null - : getSingleObject(result, id);; - } - } + private User updateUserInPass(User systemUser) throws IOException { + User passUser = systemUser.getLocatorIds().stream() + .map(this::lookupPassUser) + .filter(Objects::nonNull) + .findFirst() + .orElse(null); if (Objects.nonNull(passUser)) { - User updatedUser = passEntityUtil.update(systemUser, passUser); + User updatedUser = updateUserIfNeeded(systemUser, passUser); if (Objects.nonNull(updatedUser)) { //need to update //post COEUS processing goes here if (!updatedUser.getRoles().contains(UserRole.SUBMITTER)) { @@ -495,8 +482,7 @@ private User updateUserInPass(User systemUser) throws IOException, GrantDataExce statistics.addUsersUpdated(); return updatedUser; } - } else if (!mode.equals("user")) { //don't have a stored User for this URI - this one is new to Pass - //but don't update if we are in user mode - just update existing users + } else if (!mode.equals("user")) { passClient.createObject(systemUser); statistics.addUsersCreated(); return systemUser; @@ -504,6 +490,17 @@ private User updateUserInPass(User systemUser) throws IOException, GrantDataExce return passUser; } + private User lookupPassUser(String locatorId) { + try { + PassClientSelector selector = new PassClientSelector<>(User.class); + selector.setFilter(RSQL.hasMember("locatorIds", locatorId)); + PassClientResult result = passClient.selectObjects(selector); + return result.getObjects().isEmpty() ? null : getSingleObject(result, locatorId); + } catch (IOException | GrantDataException e) { + throw new RuntimeException(e); + } + } + /** * Take a new Grant object populated as fully as possible from the COEUS pull, and use this * new information to update an object for the same Grant in Pass (if it exists) @@ -525,7 +522,7 @@ private Grant updateGrantInPass(Grant systemGrant) throws IOException, GrantData if (!result.getObjects().isEmpty()) { LOG.debug("Found grant with localKey {}", fullLocalKey); Grant storedGrant = getSingleObject(result, fullLocalKey); - Grant updatedGrant = passEntityUtil.update(systemGrant, storedGrant); + Grant updatedGrant = updateGrantIfNeeded(systemGrant, storedGrant); if (Objects.nonNull(updatedGrant)) { //need to update passClient.updateObject(updatedGrant); statistics.addGrantsUpdated(); @@ -548,50 +545,4 @@ private T getSingleObject(PassClientResult result, Str return result.getObjects().get(0); } - /** - * This method provides the latest timestamp of all records processed. After processing, this timestamp - * will be used to be tha base timestamp for the next run of the app - * - * @return the latest update timestamp string - */ - public String getLatestUpdate() { - return this.latestUpdateString; - } - - /** - * This returns the final statistics of the processing of the Grant or User Set - * - * @return the report - */ - public String getReport() { - return statistics.getReport(); - } - - /** - * This returns the final statistics Object - useful in testing - * - * @return the statistics object - */ - public PassUpdateStatistics getStatistics() { - return statistics; - } - - public Map getGrantResultMap() { - return grantResultMap; - } - - //used in unit test - Map getFunderMap() { - return funderMap; - } - - //used in unit test - Map getUserMap() { - return userMap; - } - - void setDomain(String domain) { - this.domain = domain; - } - } diff --git a/pass-grant-loader/pass-grant-data/src/main/java/org/eclipse/pass/support/grant/data/CoeusConnector.java b/pass-grant-loader/pass-grant-data/src/main/java/org/eclipse/pass/support/grant/data/CoeusConnector.java index 7fad6f5b..585ba340 100644 --- a/pass-grant-loader/pass-grant-data/src/main/java/org/eclipse/pass/support/grant/data/CoeusConnector.java +++ b/pass-grant-loader/pass-grant-data/src/main/java/org/eclipse/pass/support/grant/data/CoeusConnector.java @@ -50,8 +50,6 @@ public class CoeusConnector implements GrantConnector { private final Properties funderPolicyProperties; - private DirectoryServiceUtil directoryServiceUtil; - /** * Class constructor. * @param connectionProperties the connection props @@ -69,7 +67,6 @@ public CoeusConnector(Properties connectionProperties, Properties funderPolicyPr if (connectionProperties.getProperty(COEUS_PASS) != null) { this.coeusPassword = connectionProperties.getProperty(COEUS_PASS); } - this.directoryServiceUtil = new DirectoryServiceUtil(connectionProperties); } this.funderPolicyProperties = funderPolicyProperties; @@ -94,7 +91,7 @@ public List> retrieveUpdates(String queryString, String mode * @return the {@code ResultSet} from the query */ private List> retrieveGrantUpdates(String queryString) - throws ClassNotFoundException, SQLException, IOException { + throws ClassNotFoundException, SQLException { List> mapList = new ArrayList<>(); @@ -130,12 +127,6 @@ private List> retrieveGrantUpdates(String queryString) rowMap.put(CoeusFieldNames.C_UPDATE_TIMESTAMP, rs.getString(CoeusFieldNames.C_UPDATE_TIMESTAMP)); rowMap.put(CoeusFieldNames.C_ABBREVIATED_ROLE, rs.getString(CoeusFieldNames.C_ABBREVIATED_ROLE)); - String employeeId = rs.getString(CoeusFieldNames.C_USER_EMPLOYEE_ID); - if (employeeId != null) { - rowMap.put(CoeusFieldNames.C_USER_HOPKINS_ID, - directoryServiceUtil.getHopkinsIdForEmployeeId(employeeId)); - } - String primaryFunderLocalKey = rs.getString(CoeusFieldNames.C_PRIMARY_FUNDER_LOCAL_KEY); rowMap.put(CoeusFieldNames.C_PRIMARY_FUNDER_LOCAL_KEY, primaryFunderLocalKey); if (primaryFunderLocalKey != null && @@ -225,18 +216,11 @@ private List> retrieveUserUpdates(String queryString) rs.getString(CoeusFieldNames.C_USER_INSTITUTIONAL_ID)); rowMap.put(CoeusFieldNames.C_USER_EMPLOYEE_ID, rs.getString(CoeusFieldNames.C_USER_EMPLOYEE_ID)); rowMap.put(CoeusFieldNames.C_UPDATE_TIMESTAMP, rs.getString(CoeusFieldNames.C_UPDATE_TIMESTAMP)); - String employeeId = rs.getString(CoeusFieldNames.C_USER_EMPLOYEE_ID); - if (employeeId != null) { - rowMap.put(CoeusFieldNames.C_USER_HOPKINS_ID, - directoryServiceUtil.getHopkinsIdForEmployeeId(employeeId)); - } LOG.debug("Record processed: {}", rowMap); if (!mapList.contains(rowMap)) { mapList.add(rowMap); } } - } catch (IOException e) { - e.printStackTrace(); } LOG.info("Retrieved result set from COEUS: {} records processed", mapList.size()); return mapList; diff --git a/pass-grant-loader/pass-grant-data/src/main/java/org/eclipse/pass/support/grant/data/CoeusPassEntityUtil.java b/pass-grant-loader/pass-grant-data/src/main/java/org/eclipse/pass/support/grant/data/CoeusPassEntityUtil.java deleted file mode 100644 index 77e02ca3..00000000 --- a/pass-grant-loader/pass-grant-data/src/main/java/org/eclipse/pass/support/grant/data/CoeusPassEntityUtil.java +++ /dev/null @@ -1,260 +0,0 @@ -/* - * Copyright 2023 Johns Hopkins University - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.eclipse.pass.support.grant.data; - -import java.util.HashSet; -import java.util.Set; -import java.util.stream.Collectors; - -import org.eclipse.pass.support.client.model.Funder; -import org.eclipse.pass.support.client.model.Grant; -import org.eclipse.pass.support.client.model.User; - -/** - * A utility class for handling Grants, Users or Funders. One function performed is comparison of two instances of - * these PASS entity classes. These comparisons are reduced to only those fields which are updatable by - * data from COEUS, so that two objects are considered "COEUS equal" iff they agree on these fields. - *

- * Another function performed by this utility class is to construct an updated version of an instance of one of these - * classes - * by merging a (possibly) existing Pass object with new information obtained from a COEUS data pull. - * - * @author jrm@jhu.edu - */ -public class CoeusPassEntityUtil implements PassEntityUtil { - - /** - * This method takes a COEUS Funder, calculates whether it needs to be updated, and if so, returns the updated - * object - * to be be ingested into the repository. if not, returns null. - * - * @param stored the Funder as it is stored in the PASS backend - * @param system the version of the Funder from the COEUS pull - * @return the updated Funder - null if the Funder does not need to be updated - */ - public Funder update(Funder system, Funder stored) { - if (funderNeedsUpdate(system, stored)) { - return updateFunder(system, stored); - } - return null; - } - - /** - * This method takes a COEUS User, calculates whether it needs to be updated, and if so, returns the updated object - * to be be ingested into the repository. if not, returns null. - * - * @param stored the User as it is stored in the PASS backend - * @param system the version of the user from the COEUS pull - * @return the updated User - null if the User does not need to be updated - */ - public User update(User system, User stored) { - if (userNeedsUpdate(system, stored)) { - return updateUser(system, stored); - } - return null; - } - - /** - * This method takes a COEUS Grant, calculates whether it needs to be updated, and if so, returns the updated object - * to be be ingested into the repository. if not, returns null. - * - * @param stored the Grant as it is stored in the PASS backend - * @param system the version of the Grant from the COEUS pull - * @return the updated object - null if the Grant does not need to be updated - */ - public Grant update(Grant system, Grant stored) { - //adjust the system view of co-pis by merging in the stored view of pi and co-pis - for (User coPiUser : stored.getCoPis()) { - if (!system.getCoPis().contains(coPiUser)) { - system.getCoPis().add(coPiUser); - } - } - - //need to be careful, system pi might be null if there is no record for it - //this is to finalize the version of the co-pi list we want to compare between - //system and stored - User storedPi = stored.getPi(); - if (system.getPi() != null) { - if (!system.getPi().equals(storedPi)) { - // stored.setPi( system.getPi() ); - if (!system.getCoPis().contains(storedPi)) { - system.getCoPis().add(storedPi); - } - system.getCoPis().remove(system.getPi()); - } - } else { //system view is null, do not trigger update based on this field - system.setPi(storedPi); - } - - //now system view has all available info we want in this grant - look for update trigger - if (grantNeedsUpdate(system, stored)) { - return updateGrant(system, stored); - } - return null; - } - - /** - * 0p - * Compare two Funder objects - * - * @param system the version of the Funder as seen in the COEUS system pull - * @param stored the version of the Funder as read from Pass - * @return a boolean which asserts whether the two supplied Funders are "COEUS equal" - */ - private boolean funderNeedsUpdate(Funder system, Funder stored) { - - //this adjustment handles the case where we take data from policy.properties file, which has no name info - if (system.getName() != null && !system.getName().equals(stored.getName())) { - return true; - } - if (system.getLocalKey() != null ? !system.getLocalKey() - .equals(stored.getLocalKey()) : stored.getLocalKey() != null) { - return true; - } - if (system.getPolicy() != null ? !system.getPolicy().equals(stored.getPolicy()) : stored.getPolicy() != null) { - return true; - } - return false; - } - - /** - * Update a Pass Funder object with new information from COEUS - * - * @param system the version of the Funder as seen in the COEUS system pull - * @param stored the version of the Funder as read from Pass - * @return the Funder object which represents the Pass object, with any new information from COEUS merged in - */ - private Funder updateFunder(Funder system, Funder stored) { - //stored.setLocalKey(system.getLocalKey()); - if (system.getName() != null) { - stored.setName(system.getName()); - } - if (system.getPolicy() != null) { - stored.setPolicy(system.getPolicy()); - } - return stored; - } - - /** - * Compare two User objects. We only care about those fields for which COEUS is the authoritative source - * After recent changes. this method would be more accurately named "storedUserDoesNotNeedToBeUpdated" - * - * @param system the version of the User as seen in the COEUS system pull - * @param stored the version of the User as read from Pass - * @return a boolean which asserts whether the two supplied Users are "COEUS equal" - */ - private boolean userNeedsUpdate(User system, User stored) { - //first the fields for which COEUS is authoritative - if (system.getFirstName() != null ? !system.getFirstName() - .equals(stored.getFirstName()) : stored.getFirstName() != null) { - return true; - } - if (system.getMiddleName() != null ? !system.getMiddleName() - .equals(stored.getMiddleName()) : stored.getMiddleName() != null) { - return true; - } - if (system.getLastName() != null ? !system.getLastName() - .equals(stored.getLastName()) : stored.getLastName() != null) { - return true; - } - if (system.getLocatorIds() != null ? !stored.getLocatorIds().containsAll( - system.getLocatorIds()) : stored.getLocatorIds() != null) { - return true; - } - //next, other fields which require some reasoning to decide whether an update is necessary - if (system.getEmail() != null && stored.getEmail() == null) { - return true; - } - if (system.getDisplayName() != null && stored.getDisplayName() == null) { - return true; - } - return false; - } - - /** - * Update a Pass User object with new information from COEUS. We check only those fields for which COEUS is - * authoritative. Other fields will be managed by other providers (Shibboleth for example). The exceptions are - * the localKey, which this application and Shibboleth both rely on; and email, which this application only - * populates - * if Shib hasn't done so already. - * - * @param system the version of the User as seen in the COEUS system pull - * @param stored the version of the User as read from Pass - * @return the User object which represents the Pass object, with any new information from COEUS merged in - */ - private User updateUser(User system, User stored) { - stored.setFirstName(system.getFirstName()); - stored.setMiddleName(system.getMiddleName()); - stored.setLastName(system.getLastName()); - //combine the locatorIds from both objects - Set idSet = new HashSet<>(); - idSet.addAll(stored.getLocatorIds()); - idSet.addAll(system.getLocatorIds()); - stored.setLocatorIds(idSet.stream().collect(Collectors.toList())); - //populate null fields if we can - if ((stored.getEmail() == null) && (system.getEmail() != null)) { - stored.setEmail(system.getEmail()); - } - if ((stored.getDisplayName() == null && system.getDisplayName() != null)) { - stored.setDisplayName(system.getDisplayName()); - } - return stored; - } - - /** - * Compare two Grant objects. Note that the Lists of Co-Pis are compared as Sets - * - * @param system the version of the Grant as seen in the COES system pull - * @param stored the version of the Grant as read from Pass - * @return a boolean which asserts whether the two supplied Grants are "COEUS equal" - */ - private boolean grantNeedsUpdate(Grant system, Grant stored) { - if (system.getAwardStatus() != null ? !system.getAwardStatus() - .equals( - stored.getAwardStatus()) : stored.getAwardStatus() != null) { - return true; - } - if (system.getPi() != null ? !system.getPi().equals(stored.getPi()) : stored.getPi() != null) { - return true; - } - if (system.getCoPis() != null ? !new HashSet(system.getCoPis()).equals( - new HashSet(stored.getCoPis())) : stored.getCoPis() != null) { - return true; - } - if (system.getEndDate() != null ? system.getEndDate() - .isAfter(stored.getEndDate()) : stored.getEndDate() != null) { - return true; - } - return false; - } - - /** - * Update a Pass Grant object with new information from COEUS - only updatable fields are considered. - * the PASS version is authoritative for the rest - * - * @param system the version of the Grant as seen in the COEUS system pull - * @param stored the version of the Grant as read from Pass - * @return the Grant object which represents the Pass object, with any new information from COEUS merged in - */ - private Grant updateGrant(Grant system, Grant stored) { - stored.setAwardStatus(system.getAwardStatus()); - stored.setPi(system.getPi()); - stored.setCoPis(system.getCoPis()); - stored.setEndDate(system.getEndDate()); - return stored; - } - -} diff --git a/pass-grant-loader/pass-grant-data/src/main/java/org/eclipse/pass/support/grant/data/CoeusPassInitEntityUtil.java b/pass-grant-loader/pass-grant-data/src/main/java/org/eclipse/pass/support/grant/data/CoeusPassInitEntityUtil.java deleted file mode 100644 index dea86e64..00000000 --- a/pass-grant-loader/pass-grant-data/src/main/java/org/eclipse/pass/support/grant/data/CoeusPassInitEntityUtil.java +++ /dev/null @@ -1,143 +0,0 @@ -/* - * Copyright 2023 Johns Hopkins University - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.eclipse.pass.support.grant.data; - -import java.util.HashSet; - -import org.eclipse.pass.support.client.model.Grant; -import org.eclipse.pass.support.client.model.User; - -/** - * This subclass is for the special case where we need to correct information on existing PASS objects for which we - * normally consider the PASS information to be authoritative. - */ -public class CoeusPassInitEntityUtil extends CoeusPassEntityUtil { - - @Override - public Grant update(Grant system, Grant stored) { - //adjust the system view of co-pis by merging in the stored view of pi and co-pis - for (User coPiUser : stored.getCoPis()) { - if (!system.getCoPis().contains(coPiUser)) { - system.getCoPis().add(coPiUser); - } - } - - //need to be careful, system pi might be null if there is no record for it - //this is to finalize the version of the co-pi list we want to compare between - //system and stored - User storedPi = stored.getPi(); - if (system.getPi() != null) { - if (!system.getPi().equals(storedPi)) { - // stored.setPi( system.getPi() ); - if (!system.getCoPis().contains(storedPi)) { - system.getCoPis().add(storedPi); - } - system.getCoPis().remove(system.getPi()); - } - } else { //system view is null, do not trigger update based on this field - system.setPi(storedPi); - } - - //now system view has all available info we want in this grant - look for update trigger - if (this.grantNeedsUpdate(system, stored)) { - return this.updateGrant(system, stored); - } - return null; - } - - /** - * Compare two Grant objects. Note that the Lists of Co-Pis are compared as Sets - * - * @param system the version of the Grant as seen in the COEUS system pull - * @param stored the version of the Grant as read from Pass - * @return a boolean which asserts whether the stored grant needs to be updated - */ - - private boolean grantNeedsUpdate(Grant system, Grant stored) { - if (system.getAwardNumber() != null ? !system.getAwardNumber() - .equals( - stored.getAwardNumber()) : stored.getAwardNumber() != null) { - return true; - } - if (system.getAwardStatus() != null ? !system.getAwardStatus() - .equals( - stored.getAwardStatus()) : stored.getAwardStatus() != null) { - return true; - } - if (system.getLocalKey() != null ? !system.getLocalKey() - .equals(stored.getLocalKey()) : stored.getLocalKey() != null) { - return true; - } - if (system.getProjectName() != null ? !system.getProjectName() - .equals( - stored.getProjectName()) : stored.getProjectName() != null) { - return true; - } - if (system.getPrimaryFunder() != null ? !system.getPrimaryFunder().equals( - stored.getPrimaryFunder()) : stored.getPrimaryFunder() != null) { - return true; - } - if (system.getDirectFunder() != null ? !system.getDirectFunder().equals( - stored.getDirectFunder()) : stored.getDirectFunder() != null) { - return true; - } - if (system.getPi() != null ? !system.getPi().equals(stored.getPi()) : stored.getPi() != null) { - return true; - } - if (system.getCoPis() != null ? !new HashSet(system.getCoPis()).equals( - new HashSet(stored.getCoPis())) : stored.getCoPis() != null) { - return true; - } - if (system.getAwardDate() != null ? system.getAwardDate() - .isBefore(stored.getAwardDate()) : stored.getAwardDate() != null) { - return true; - } - if (system.getStartDate() != null ? system.getStartDate() - .isBefore(stored.getStartDate()) : stored.getStartDate() != null) { - return true; - } - if (system.getEndDate() != null ? system.getEndDate() - .isAfter(stored.getEndDate()) : stored.getEndDate() != null) { - return true; - } - return false; - } - - /** - * Update a Pass Grant object with new information from COEUS - * - * @param system the version of the Grant as seen in the COEUS system pull - * @param stored the version of the Grant as read from Pass - * @return the Grant object which represents the Pass object, with any new information from COEUS merged in - */ - private Grant updateGrant(Grant system, Grant stored) { - stored.setAwardNumber(system.getAwardNumber()); - stored.setAwardStatus(system.getAwardStatus()); - stored.setLocalKey(system.getLocalKey()); - stored.setProjectName(system.getProjectName()); - stored.setPrimaryFunder(system.getPrimaryFunder()); - stored.setDirectFunder(system.getDirectFunder()); - stored.setPi(system.getPi()); - stored.setCoPis(system.getCoPis()); - - //since this is essentially an initial pull, we can just take the system values - stored.setAwardDate(system.getAwardDate()); - stored.setStartDate(system.getStartDate()); - stored.setEndDate(system.getEndDate()); - return stored; - } - -} diff --git a/pass-grant-loader/pass-grant-data/src/main/java/org/eclipse/pass/support/grant/data/DifferenceLogger.java b/pass-grant-loader/pass-grant-data/src/main/java/org/eclipse/pass/support/grant/data/DifferenceLogger.java new file mode 100644 index 00000000..4e9f368e --- /dev/null +++ b/pass-grant-loader/pass-grant-data/src/main/java/org/eclipse/pass/support/grant/data/DifferenceLogger.java @@ -0,0 +1,90 @@ +/* + * Copyright 2023 Johns Hopkins University + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.eclipse.pass.support.grant.data; + +import java.lang.reflect.Field; +import java.util.ArrayList; +import java.util.List; +import java.util.Objects; +import java.util.Set; +import java.util.stream.Collectors; + +import org.eclipse.pass.support.client.model.PassEntity; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * @author Russ Poetker (rpoetke1@jh.edu) + */ +public class DifferenceLogger { + + private static final Logger LOG = LoggerFactory.getLogger(DifferenceLogger.class); + + /** + * Logs the difference in attribute values between the source and target PassEntities. + * + * @param source the existing PassEntity state + * @param target the updated PassEntity state + */ + public void log(PassEntity source, PassEntity target) { + LOG.info("Updated " + source.getClass().getSimpleName() + " with ID: " + source.getId()); + if (LOG.isInfoEnabled()) { + List diffs = getDifference(source, target, source.getId()); + diffs.forEach(LOG::info); + } + } + + @SuppressWarnings("unchecked") + private List getDifference(Object s1, Object s2, String grantId) { + List values = new ArrayList<>(); + try { + for (Field field : s1.getClass().getDeclaredFields()) { + field.setAccessible(true); + Object value1 = field.get(s1); + Object value2 = field.get(s2); + if (value1 instanceof PassEntity || value2 instanceof PassEntity) { + getPassEntityDiffs((PassEntity) value1, (PassEntity) value2, values, field); + } else if (value1 instanceof List || value2 instanceof List) { + getListDiffs((List) value1, (List) value2, values, field); + } else if (!Objects.equals(value1, value2)) { + values.add(field.getName() + ": " + value1 + " -> " + value2); + } + } + } catch (IllegalAccessException e) { + LOG.error("Error printing diffs Grant ID: " + grantId, e); + } + return values; + } + + private void getPassEntityDiffs(PassEntity value1, PassEntity value2, List values, Field field) { + String funder1Id = Objects.nonNull(value1) ? value1.getId() : null; + String funder2Id = Objects.nonNull(value2) ? value2.getId() : null; + if (!Objects.equals(funder1Id, funder2Id)) { + values.add(field.getName() + " IDs: " + funder1Id + " -> " + funder2Id); + } + } + + private void getListDiffs(List value1, List value2, List values, Field field) { + Set coPiIds1 = Objects.nonNull(value1) ? + value1.stream().map(PassEntity::getId).collect(Collectors.toSet()) : null; + Set coPiIds2 = Objects.nonNull(value2) ? + value2.stream().map(PassEntity::getId).collect(Collectors.toSet()) : null; + if (!Objects.equals(coPiIds1, coPiIds2)) { + values.add(field.getName() + " IDs: " + coPiIds1 + " -> " + coPiIds2); + } + } + +} diff --git a/pass-grant-loader/pass-grant-data/src/main/java/org/eclipse/pass/support/grant/data/DirectoryServiceUtil.java b/pass-grant-loader/pass-grant-data/src/main/java/org/eclipse/pass/support/grant/data/DirectoryServiceUtil.java deleted file mode 100644 index b2ce27fd..00000000 --- a/pass-grant-loader/pass-grant-data/src/main/java/org/eclipse/pass/support/grant/data/DirectoryServiceUtil.java +++ /dev/null @@ -1,182 +0,0 @@ -/* - * Copyright 2023 Johns Hopkins University - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.eclipse.pass.support.grant.data; - -import static java.util.concurrent.TimeUnit.SECONDS; - -import java.io.IOException; -import java.util.HashMap; -import java.util.Map; -import java.util.Objects; -import java.util.Properties; - -import com.fasterxml.jackson.core.JsonFactory; -import com.fasterxml.jackson.core.JsonParser; -import com.fasterxml.jackson.core.JsonToken; -import okhttp3.HttpUrl; -import okhttp3.OkHttpClient; -import okhttp3.Request; -import okhttp3.Response; - -/** - * This util class is designed to hit a service which provides resolution of one identifier to another. The two - * endpoints - * provide lookups between our Hopkins Id, which is a durable identifier for all members of the Hopkins community, - * and the - * employee ID, which is a durable identifier for all Hopkins employees. This lookup service is necessary because we - * do not - * have access to the wider identifier in our grants data source. - * - * @author jrm - */ -class DirectoryServiceUtil { - - static final String DIRECTORY_SERVICE_BASE_URL = "directory.base.url"; - static final String DIRECTORY_SERVICE_CLIENT_ID = "directory.client.id"; - static final String DIRECTORY_SERVICE_CLIENT_SECRET = "directory.client.secret"; - - private String directoryBaseUrl; - private String directoryClientId; - private String directoryClientSecret; - - private final OkHttpClient client; - private final JsonFactory factory = new JsonFactory(); - - //these are for caching results - private final Map hopkins2ee = new HashMap<>(); - private final Map ee2hopkins = new HashMap<>(); - - DirectoryServiceUtil(Properties connectionProperties) { - if (connectionProperties != null) { - - if (connectionProperties.getProperty(DIRECTORY_SERVICE_BASE_URL) != null) { - this.directoryBaseUrl = connectionProperties.getProperty(DIRECTORY_SERVICE_BASE_URL); - } - if (connectionProperties.getProperty(DIRECTORY_SERVICE_CLIENT_ID) != null) { - this.directoryClientId = connectionProperties.getProperty(DIRECTORY_SERVICE_CLIENT_ID); - } - if (connectionProperties.getProperty(DIRECTORY_SERVICE_CLIENT_SECRET) != null) { - this.directoryClientSecret = connectionProperties.getProperty(DIRECTORY_SERVICE_CLIENT_SECRET); - } - } - OkHttpClient.Builder builder = new OkHttpClient.Builder(); - builder.connectTimeout(30, SECONDS); - builder.readTimeout(30, SECONDS); - builder.writeTimeout(30, SECONDS); - client = builder.build(); - } - - /** - * an enum to hold values for the service URL ending, and the query parameter name - * for these lookup services - */ - private enum Type { - EMPLOYEE2HOPKINS("EmployeeID_to_HopkinsID", "employeeid"), - HOPKINS2EMPLOYEE("HopkinsID_to_EmployeeID", "hopkinsid"); - - private final String serviceUrlEnding; - private final String queryParameter; - - Type(String serviceUrlEnding, String queryParameter) { - this.serviceUrlEnding = serviceUrlEnding; - this.queryParameter = queryParameter; - } - - public String getServiceUrlEnding() { - return serviceUrlEnding; - } - - public String getQueryParameter() { - return queryParameter; - } - } - - /** - * Return Hopkins ID for a given employee ID. we cache lookups in a map so that we only need to perform - * a lookup once per session per user. - * - * @param employeeId the user's employeeId - * @return the user's Hopkins ID - should never be null - * @throws IOException if the service cannot be reached - */ - String getHopkinsIdForEmployeeId(String employeeId) throws IOException { - String hopkinsId; - if (!ee2hopkins.containsKey(employeeId)) { - hopkinsId = askDirectoryForMappedValue(Type.EMPLOYEE2HOPKINS, employeeId); - ee2hopkins.put(employeeId, hopkinsId); - } else { - hopkinsId = ee2hopkins.get(employeeId); - } - return hopkinsId; - } - - /** - * Return employee ID for a given Hopkins ID. we cache lookups in a map so that we only need to perform - * a lookup once per session per user. - * - * @param hopkinsId the user's Hopkins ID - * @return the user's employee ID if it exists; null if it does not - * @throws IOException if there is an IO exception - */ - String getEmployeeIdForHopkinsId(String hopkinsId) throws IOException { - String employeeId; - if (!hopkins2ee.containsKey(hopkinsId)) { - employeeId = askDirectoryForMappedValue(Type.HOPKINS2EMPLOYEE, hopkinsId); - hopkins2ee.put(hopkinsId, employeeId); - } else { - employeeId = hopkins2ee.get(hopkinsId); - } - return employeeId; - } - - private String askDirectoryForMappedValue(Type type, String sourceId) throws IOException { - String name = type.getQueryParameter(); - String suffix = type.getServiceUrlEnding(); - String serviceUrl; - if (!directoryBaseUrl.endsWith("/")) { - directoryBaseUrl = directoryBaseUrl + "/"; - } - serviceUrl = directoryBaseUrl + suffix; - - HttpUrl.Builder urlBuilder = Objects.requireNonNull(HttpUrl.parse(serviceUrl)).newBuilder() - .addQueryParameter(name, sourceId); - String url = urlBuilder.build().toString(); - - Request request = new Request.Builder().header("client_id", directoryClientId) - .header("client_secret", directoryClientSecret).url(url).build(); - - Response response = client.newCall(request).execute(); - - assert response.body() != null; - JsonParser parser = factory.createParser(response.body().string()); - String mappedValue = null; - while (!parser.isClosed()) { - JsonToken jsonToken = parser.nextToken(); - if (JsonToken.FIELD_NAME.equals(jsonToken)) { - String fieldName = parser.getCurrentName(); - parser.nextToken(); - if (sourceId.equals(fieldName)) { - mappedValue = parser.getValueAsString(); - mappedValue = mappedValue.equals("NULL") ? null : mappedValue; - } - } - } - - return mappedValue; - - } - -} diff --git a/pass-grant-loader/pass-grant-data/src/main/java/org/eclipse/pass/support/grant/data/JhuPassInitUpdater.java b/pass-grant-loader/pass-grant-data/src/main/java/org/eclipse/pass/support/grant/data/JhuPassInitUpdater.java index aad4792d..6cefe8ca 100644 --- a/pass-grant-loader/pass-grant-data/src/main/java/org/eclipse/pass/support/grant/data/JhuPassInitUpdater.java +++ b/pass-grant-loader/pass-grant-data/src/main/java/org/eclipse/pass/support/grant/data/JhuPassInitUpdater.java @@ -15,82 +15,138 @@ */ package org.eclipse.pass.support.grant.data; -import static org.eclipse.pass.support.grant.data.CoeusFieldNames.C_USER_EMAIL; -import static org.eclipse.pass.support.grant.data.CoeusFieldNames.C_USER_EMPLOYEE_ID; -import static org.eclipse.pass.support.grant.data.CoeusFieldNames.C_USER_FIRST_NAME; -import static org.eclipse.pass.support.grant.data.CoeusFieldNames.C_USER_HOPKINS_ID; -import static org.eclipse.pass.support.grant.data.CoeusFieldNames.C_USER_INSTITUTIONAL_ID; -import static org.eclipse.pass.support.grant.data.CoeusFieldNames.C_USER_LAST_NAME; -import static org.eclipse.pass.support.grant.data.CoeusFieldNames.C_USER_MIDDLE_NAME; +import java.util.HashSet; -import java.util.Map; - -import org.eclipse.pass.support.client.PassClient; +import org.eclipse.pass.support.client.model.Grant; import org.eclipse.pass.support.client.model.User; -import org.eclipse.pass.support.client.model.UserRole; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; /** * The Init Grant Pass Updater for data sourced from Jhu Coeus. */ -public class JhuPassInitUpdater extends DefaultPassUpdater { +public class JhuPassInitUpdater extends JhuPassUpdater { - private static final Logger LOG = LoggerFactory.getLogger(JhuPassInitUpdater.class); - private static final String DOMAIN = "johnshopkins.edu"; - private static final String EMPLOYEE_ID_TYPE = "employeeid"; - private static final String HOPKINS_ID_TYPE = "unique-id"; - private static final String JHED_ID_TYPE = "eppn"; + private final DifferenceLogger differenceLogger; /** - * Class constructor. - * @param passClient a client instance for Pass + * Default constructor. */ - public JhuPassInitUpdater(PassClient passClient) { - super(new CoeusPassInitEntityUtil(), passClient); - super.setDomain(DOMAIN); + public JhuPassInitUpdater() { + differenceLogger = new DifferenceLogger(); + } + + @Override + public Grant updateGrantIfNeeded(Grant system, Grant stored) { + //adjust the system view of co-pis by merging in the stored view of pi and co-pis + for (User coPiUser : stored.getCoPis()) { + if (!system.getCoPis().contains(coPiUser)) { + system.getCoPis().add(coPiUser); + } + } + + //need to be careful, system pi might be null if there is no record for it + //this is to finalize the version of the co-pi list we want to compare between + //system and stored + User storedPi = stored.getPi(); + if (system.getPi() != null) { + if (!system.getPi().equals(storedPi)) { + // stored.setPi( system.getPi() ); + if (!system.getCoPis().contains(storedPi)) { + system.getCoPis().add(storedPi); + } + system.getCoPis().remove(system.getPi()); + } + } else { //system view is null, do not trigger update based on this field + system.setPi(storedPi); + } + + //now system view has all available info we want in this grant - look for update trigger + if (this.grantNeedsUpdate(system, stored)) { + return this.updateGrant(system, stored); + } + return null; } /** - * Default class constructor. + * Compare two Grant objects. Note that the Lists of Co-Pis are compared as Sets + * + * @param system the version of the Grant as seen in the COEUS system pull + * @param stored the version of the Grant as read from Pass + * @return a boolean which asserts whether the stored grant needs to be updated */ - public JhuPassInitUpdater() { - super(new CoeusPassInitEntityUtil()); - super.setDomain(DOMAIN); - } - @Override - User buildUser(Map rowMap) { - User user = new User(); - user.setFirstName(rowMap.get(C_USER_FIRST_NAME)); - if (rowMap.containsKey(C_USER_MIDDLE_NAME)) { - user.setMiddleName(rowMap.get(C_USER_MIDDLE_NAME)); + private boolean grantNeedsUpdate(Grant system, Grant stored) { + if (system.getAwardNumber() != null ? !system.getAwardNumber() + .equals( + stored.getAwardNumber()) : stored.getAwardNumber() != null) { + return true; + } + if (system.getAwardStatus() != null ? !system.getAwardStatus() + .equals( + stored.getAwardStatus()) : stored.getAwardStatus() != null) { + return true; + } + if (system.getLocalKey() != null ? !system.getLocalKey() + .equals(stored.getLocalKey()) : stored.getLocalKey() != null) { + return true; + } + if (system.getProjectName() != null ? !system.getProjectName() + .equals( + stored.getProjectName()) : stored.getProjectName() != null) { + return true; + } + if (system.getPrimaryFunder() != null ? !system.getPrimaryFunder().equals( + stored.getPrimaryFunder()) : stored.getPrimaryFunder() != null) { + return true; + } + if (system.getDirectFunder() != null ? !system.getDirectFunder().equals( + stored.getDirectFunder()) : stored.getDirectFunder() != null) { + return true; } - user.setLastName(rowMap.get(C_USER_LAST_NAME)); - user.setDisplayName(rowMap.get(C_USER_FIRST_NAME) + " " + rowMap.get(C_USER_LAST_NAME)); - user.setEmail(rowMap.get(C_USER_EMAIL)); - String employeeId = rowMap.get(C_USER_EMPLOYEE_ID); - String hopkinsId = null; - if (rowMap.containsKey(C_USER_HOPKINS_ID)) { - hopkinsId = rowMap.get(C_USER_HOPKINS_ID); + if (system.getPi() != null ? !system.getPi().equals(stored.getPi()) : stored.getPi() != null) { + return true; } - String jhedId = null; - if (rowMap.get(C_USER_INSTITUTIONAL_ID) != null) { - jhedId = rowMap.get(C_USER_INSTITUTIONAL_ID).toLowerCase(); + if (system.getCoPis() != null ? !new HashSet(system.getCoPis()).equals( + new HashSet(stored.getCoPis())) : stored.getCoPis() != null) { + return true; } - //Build the List of locatorIds - put the most reliable ids first - if (employeeId != null) { - user.getLocatorIds().add(GrantDataUtils.buildLocalKey(DOMAIN, EMPLOYEE_ID_TYPE, employeeId)); + if (system.getAwardDate() != null ? system.getAwardDate() + .isBefore(stored.getAwardDate()) : stored.getAwardDate() != null) { + return true; } - if (hopkinsId != null) { - user.getLocatorIds().add(GrantDataUtils.buildLocalKey(DOMAIN, HOPKINS_ID_TYPE, hopkinsId)); + if (system.getStartDate() != null ? system.getStartDate() + .isBefore(stored.getStartDate()) : stored.getStartDate() != null) { + return true; } - if (jhedId != null) { - user.getLocatorIds().add(GrantDataUtils.buildLocalKey(DOMAIN, JHED_ID_TYPE, jhedId)); + if (system.getEndDate() != null ? system.getEndDate() + .isAfter(stored.getEndDate()) : stored.getEndDate() != null) { + return true; } - user.getRoles().add(UserRole.SUBMITTER); - LOG.debug("Built user with employee ID {}", employeeId); - return user; + return false; + } + + /** + * Update a Pass Grant object with new information from COEUS + * + * @param system the version of the Grant as seen in the COEUS system pull + * @param stored the version of the Grant as read from Pass + * @return the Grant object which represents the Pass object, with any new information from COEUS merged in + */ + private Grant updateGrant(Grant system, Grant stored) { + differenceLogger.log(system, stored); + stored.setAwardNumber(system.getAwardNumber()); + stored.setAwardStatus(system.getAwardStatus()); + stored.setLocalKey(system.getLocalKey()); + stored.setProjectName(system.getProjectName()); + stored.setPrimaryFunder(system.getPrimaryFunder()); + stored.setDirectFunder(system.getDirectFunder()); + stored.setPi(system.getPi()); + stored.setCoPis(system.getCoPis()); + + //since this is essentially an initial pull, we can just take the system values + stored.setAwardDate(system.getAwardDate()); + stored.setStartDate(system.getStartDate()); + stored.setEndDate(system.getEndDate()); + return stored; } } diff --git a/pass-grant-loader/pass-grant-data/src/main/java/org/eclipse/pass/support/grant/data/JhuPassUpdater.java b/pass-grant-loader/pass-grant-data/src/main/java/org/eclipse/pass/support/grant/data/JhuPassUpdater.java index b44d928f..28887913 100644 --- a/pass-grant-loader/pass-grant-data/src/main/java/org/eclipse/pass/support/grant/data/JhuPassUpdater.java +++ b/pass-grant-loader/pass-grant-data/src/main/java/org/eclipse/pass/support/grant/data/JhuPassUpdater.java @@ -18,14 +18,17 @@ import static org.eclipse.pass.support.grant.data.CoeusFieldNames.C_USER_EMAIL; import static org.eclipse.pass.support.grant.data.CoeusFieldNames.C_USER_EMPLOYEE_ID; import static org.eclipse.pass.support.grant.data.CoeusFieldNames.C_USER_FIRST_NAME; -import static org.eclipse.pass.support.grant.data.CoeusFieldNames.C_USER_HOPKINS_ID; import static org.eclipse.pass.support.grant.data.CoeusFieldNames.C_USER_INSTITUTIONAL_ID; import static org.eclipse.pass.support.grant.data.CoeusFieldNames.C_USER_LAST_NAME; import static org.eclipse.pass.support.grant.data.CoeusFieldNames.C_USER_MIDDLE_NAME; +import java.util.HashSet; import java.util.Map; +import java.util.Objects; +import java.util.Set; -import org.eclipse.pass.support.client.PassClient; +import org.eclipse.pass.support.client.model.Funder; +import org.eclipse.pass.support.client.model.Grant; import org.eclipse.pass.support.client.model.User; import org.eclipse.pass.support.client.model.UserRole; import org.slf4j.Logger; @@ -37,33 +40,81 @@ * * @author jrm@jhu.edu */ -public class JhuPassUpdater extends DefaultPassUpdater { +public class JhuPassUpdater extends AbstractDefaultPassUpdater { private static final Logger LOG = LoggerFactory.getLogger(JhuPassUpdater.class); private static final String DOMAIN = "johnshopkins.edu"; private static final String EMPLOYEE_ID_TYPE = "employeeid"; - private static final String HOPKINS_ID_TYPE = "unique-id"; private static final String JHED_ID_TYPE = "eppn"; - /** - * Class constructor. - * @param passClient a client instance for Pass - */ - public JhuPassUpdater(PassClient passClient) { - super(new CoeusPassEntityUtil(), passClient); - super.setDomain(DOMAIN); - } + static final String EMPLOYEE_LOCATOR_ID = DOMAIN + ":" + EMPLOYEE_ID_TYPE + ":"; + static final String JHED_LOCATOR_ID = DOMAIN + ":" + JHED_ID_TYPE + ":"; /** - * Default class constructor. + * Constructor. */ public JhuPassUpdater() { - super(new CoeusPassEntityUtil()); - super.setDomain(DOMAIN); + setDomain(DOMAIN); + } + + @Override + public Grant updateGrantIfNeeded(Grant system, Grant stored) { + //adjust the system view of co-pis by merging in the stored view of pi and co-pis + for (User coPiUser : stored.getCoPis()) { + if (!system.getCoPis().contains(coPiUser)) { + system.getCoPis().add(coPiUser); + } + } + + //need to be careful, system pi might be null if there is no record for it + //this is to finalize the version of the co-pi list we want to compare between + //system and stored + User storedPi = stored.getPi(); + if (system.getPi() != null) { + if (!system.getPi().equals(storedPi)) { + // stored.setPi( system.getPi() ); + if (!system.getCoPis().contains(storedPi)) { + system.getCoPis().add(storedPi); + } + system.getCoPis().remove(system.getPi()); + } + } else { //system view is null, do not trigger update based on this field + system.setPi(storedPi); + } + + //now system view has all available info we want in this grant - look for update trigger + if (grantNeedsUpdate(system, stored)) { + return updateGrant(system, stored); + } + return null; + } + + @Override + public Funder updateFunderIfNeeded(Funder system, Funder stored) { + if (funderNeedsUpdate(system, stored)) { + return updateFunder(system, stored); + } + return null; + } + + @Override + public User updateUserIfNeeded(User system, User stored) { + if (userNeedsUpdate(system, stored)) { + return updateUser(system, stored); + } + return null; + } + + @Override + public String getEmployeeLocatorId(User user) throws GrantDataException { + return user.getLocatorIds().stream() + .filter(locatorId -> locatorId.startsWith(EMPLOYEE_LOCATOR_ID)) + .findFirst() + .orElseThrow(() -> new GrantDataException("Unable to find employee id locator id")); } @Override - User buildUser(Map rowMap) { + public User buildUser(Map rowMap) { User user = new User(); user.setFirstName(rowMap.get(C_USER_FIRST_NAME)); if (rowMap.containsKey(C_USER_MIDDLE_NAME)) { @@ -73,27 +124,159 @@ User buildUser(Map rowMap) { user.setDisplayName(rowMap.get(C_USER_FIRST_NAME) + " " + rowMap.get(C_USER_LAST_NAME)); user.setEmail(rowMap.get(C_USER_EMAIL)); String employeeId = rowMap.get(C_USER_EMPLOYEE_ID); - String hopkinsId = null; - if (rowMap.containsKey(C_USER_HOPKINS_ID)) { - hopkinsId = rowMap.get(C_USER_HOPKINS_ID); - } String jhedId = null; if (rowMap.get(C_USER_INSTITUTIONAL_ID) != null) { jhedId = rowMap.get(C_USER_INSTITUTIONAL_ID).toLowerCase(); } //Build the List of locatorIds - put the most reliable ids first if (employeeId != null) { - user.getLocatorIds().add(GrantDataUtils.buildLocalKey(DOMAIN, EMPLOYEE_ID_TYPE, employeeId)); - } - if (hopkinsId != null) { - user.getLocatorIds().add(GrantDataUtils.buildLocalKey(DOMAIN, HOPKINS_ID_TYPE, hopkinsId)); + user.getLocatorIds().add(EMPLOYEE_LOCATOR_ID + employeeId); } if (jhedId != null) { - user.getLocatorIds().add(GrantDataUtils.buildLocalKey(DOMAIN, JHED_ID_TYPE, jhedId)); + user.getLocatorIds().add(JHED_LOCATOR_ID + jhedId); } user.getRoles().add(UserRole.SUBMITTER); LOG.debug("Built user with employee ID {}", employeeId); return user; } + private boolean funderNeedsUpdate(Funder system, Funder stored) { + + //this adjustment handles the case where we take data from policy.properties file, which has no name info + if (system.getName() != null && !system.getName().equals(stored.getName())) { + return true; + } + if (system.getLocalKey() != null ? !system.getLocalKey() + .equals(stored.getLocalKey()) : stored.getLocalKey() != null) { + return true; + } + if (system.getPolicy() != null ? !system.getPolicy().equals(stored.getPolicy()) : stored.getPolicy() != null) { + return true; + } + return false; + } + + private Funder updateFunder(Funder system, Funder stored) { + //stored.setLocalKey(system.getLocalKey()); + if (system.getName() != null) { + stored.setName(system.getName()); + } + if (system.getPolicy() != null) { + stored.setPolicy(system.getPolicy()); + } + return stored; + } + + private boolean userNeedsUpdate(User system, User stored) { + //first the fields for which COEUS is authoritative + if (system.getFirstName() != null ? !system.getFirstName() + .equals(stored.getFirstName()) : stored.getFirstName() != null) { + return true; + } + if (system.getMiddleName() != null ? !system.getMiddleName() + .equals(stored.getMiddleName()) : stored.getMiddleName() != null) { + return true; + } + if (system.getLastName() != null ? !system.getLastName() + .equals(stored.getLastName()) : stored.getLastName() != null) { + return true; + } + String systemUserJhedLocatorId = findLocatorId(system, JhuPassUpdater.JHED_LOCATOR_ID); + if (Objects.nonNull(systemUserJhedLocatorId) && !stored.getLocatorIds().contains(systemUserJhedLocatorId)) { + return true; + } + //next, other fields which require some reasoning to decide whether an update is necessary + if (system.getEmail() != null && stored.getEmail() == null) { + return true; + } + if (system.getDisplayName() != null && stored.getDisplayName() == null) { + return true; + } + return false; + } + + private String findLocatorId(User user, String locatorIdPrefix) { + return user.getLocatorIds().stream() + .filter(locatorId -> locatorId.startsWith(locatorIdPrefix)) + .findFirst() + .orElse(null); + } + + /** + * Update a Pass User object with new information from COEUS. We check only those fields for which COEUS is + * authoritative. Other fields will be managed by other providers (Shibboleth for example). The exceptions are + * the localKey, which this application and Shibboleth both rely on; and email, which this application only + * populates + * if Shib hasn't done so already. + * + * @param system the version of the User as seen in the COEUS system pull + * @param stored the version of the User as read from Pass + * @return the User object which represents the Pass object, with any new information from COEUS merged in + */ + private User updateUser(User system, User stored) { + stored.setFirstName(system.getFirstName()); + stored.setMiddleName(system.getMiddleName()); + stored.setLastName(system.getLastName()); + //combine the locatorIds from both objects + Set idSet = new HashSet<>(); + idSet.addAll(stored.getLocatorIds()); + idSet.addAll(system.getLocatorIds()); + String systemUserJhedLocatorId = findLocatorId(system, JhuPassUpdater.JHED_LOCATOR_ID); + if (Objects.nonNull(systemUserJhedLocatorId) && !stored.getLocatorIds().contains(systemUserJhedLocatorId)) { + stored.getLocatorIds().removeIf(locatorId -> locatorId.startsWith(JhuPassUpdater.JHED_LOCATOR_ID)); + stored.getLocatorIds().add(systemUserJhedLocatorId); + } + //populate null fields if we can + if ((stored.getEmail() == null) && (system.getEmail() != null)) { + stored.setEmail(system.getEmail()); + } + if ((stored.getDisplayName() == null && system.getDisplayName() != null)) { + stored.setDisplayName(system.getDisplayName()); + } + return stored; + } + + /** + * Compare two Grant objects. Note that the Lists of Co-Pis are compared as Sets + * + * @param system the version of the Grant as seen in the COES system pull + * @param stored the version of the Grant as read from Pass + * @return a boolean which asserts whether the two supplied Grants are "COEUS equal" + */ + private boolean grantNeedsUpdate(Grant system, Grant stored) { + if (system.getAwardStatus() != null ? !system.getAwardStatus() + .equals( + stored.getAwardStatus()) : stored.getAwardStatus() != null) { + return true; + } + if (system.getPi() != null ? !system.getPi().equals(stored.getPi()) : stored.getPi() != null) { + return true; + } + if (system.getCoPis() != null ? !new HashSet(system.getCoPis()).equals( + new HashSet(stored.getCoPis())) : stored.getCoPis() != null) { + return true; + } + if (system.getEndDate() != null ? system.getEndDate() + .isAfter(stored.getEndDate()) : stored.getEndDate() != null) { + return true; + } + return false; + } + + /** + * Update a Pass Grant object with new information from COEUS - only updatable fields are considered. + * the PASS version is authoritative for the rest + * + * @param system the version of the Grant as seen in the COEUS system pull + * @param stored the version of the Grant as read from Pass + * @return the Grant object which represents the Pass object, with any new information from COEUS merged in + */ + private Grant updateGrant(Grant system, Grant stored) { + stored.setAwardStatus(system.getAwardStatus()); + stored.setPi(system.getPi()); + stored.setCoPis(system.getCoPis()); + stored.setEndDate(system.getEndDate()); + return stored; + } + } diff --git a/pass-grant-loader/pass-grant-data/src/main/java/org/eclipse/pass/support/grant/data/PassEntityUtil.java b/pass-grant-loader/pass-grant-data/src/main/java/org/eclipse/pass/support/grant/data/PassEntityUtil.java deleted file mode 100644 index 09616508..00000000 --- a/pass-grant-loader/pass-grant-data/src/main/java/org/eclipse/pass/support/grant/data/PassEntityUtil.java +++ /dev/null @@ -1,65 +0,0 @@ -/* - * Copyright 2023 Johns Hopkins University - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.eclipse.pass.support.grant.data; - -import org.eclipse.pass.support.client.model.Funder; -import org.eclipse.pass.support.client.model.Grant; -import org.eclipse.pass.support.client.model.User; - -/** - * This interface defines update methods for existing (stored) grants, users and funders. In practice, - * implementations will generally - * split this functionalite into two steps - the first step will reason over a stored object and the object developed - * in a system pull, - * and make th decision whether the object needs to be updated. The update methods eill act on that decision - * appropriately. - */ -public interface PassEntityUtil { - - /** - * This method takes a Funder from the data source, calculates whether it needs to be updated, and if so, returns - * the updated object - * to be be ingested into the repository. if not, returns null. - * - * @param stored the Funder as it is stored in the PASS backend - * @param system the version of the Funder from the data sourcee pull - * @return the updated Funder - null if the Funder does not need to be updated - */ - Funder update(Funder system, Funder stored); - - /** - * This method takes a User from the data source, calculates whether it needs to be updated, and if so, returns - * the updated object - * to be be ingested into the repository. if not, returns null. - * - * @param stored the User as it is stored in the PASS backend - * @param system the version of the User from the data sourcee pull - * @return the updated User - null if the User does not need to be updated - */ - User update(User system, User stored); - - /** - * This method takes a Grantfrom the data source, calculates whether it needs to be updated, and if so, returns - * the updated object - * to be be ingested into the repository. if not, returns null. - * - * @param stored the Grant as it is stored in the PASS backend - * @param system the version of the Grant from the data sourcee pull - * @return the updated Grant - null if the Grant does not need to be updated - */ - Grant update(Grant system, Grant stored); - -} diff --git a/pass-grant-loader/pass-grant-data/src/main/java/org/eclipse/pass/support/grant/data/PassUpdater.java b/pass-grant-loader/pass-grant-data/src/main/java/org/eclipse/pass/support/grant/data/PassUpdater.java index e7fab98f..02eb2156 100644 --- a/pass-grant-loader/pass-grant-data/src/main/java/org/eclipse/pass/support/grant/data/PassUpdater.java +++ b/pass-grant-loader/pass-grant-data/src/main/java/org/eclipse/pass/support/grant/data/PassUpdater.java @@ -18,7 +18,9 @@ import java.util.Collection; import java.util.Map; +import org.eclipse.pass.support.client.model.Funder; import org.eclipse.pass.support.client.model.Grant; +import org.eclipse.pass.support.client.model.User; /** * An interface specifying behavior of a class that processes grant data into PASS. @@ -32,6 +34,54 @@ public interface PassUpdater { */ void updatePass(Collection> results, String mode); + /** + * This method takes a Grantfrom the data source, calculates whether it needs to be updated, and if so, returns + * the updated object + * to be be ingested into the repository. if not, returns null. + * + * @param stored the Grant as it is stored in the PASS backend + * @param system the version of the Grant from the data sourcee pull + * @return the updated Grant - null if the Grant does not need to be updated + */ + Grant updateGrantIfNeeded(Grant system, Grant stored); + + /** + * This method takes a Funder from the data source, calculates whether it needs to be updated, and if so, returns + * the updated object + * to be be ingested into the repository. if not, returns null. + * + * @param stored the Funder as it is stored in the PASS backend + * @param system the version of the Funder from the data sourcee pull + * @return the updated Funder - null if the Funder does not need to be updated + */ + Funder updateFunderIfNeeded(Funder system, Funder stored); + + /** + * This method takes a User from the data source, calculates whether it needs to be updated, and if so, returns + * the updated object + * to be be ingested into the repository. if not, returns null. + * + * @param stored the User as it is stored in the PASS backend + * @param system the version of the User from the data sourcee pull + * @return the updated User - null if the User does not need to be updated + */ + User updateUserIfNeeded(User system, User stored); + + /** + * Build a User for the institution based on the result set Map. + * @param rowMap a result set map + * @return a User + */ + User buildUser(Map rowMap); + + /** + * Returns the employee locator ID of the user. + * @param user the user + * @return the employee id + * @throws GrantDataException of the employee ID is not found + */ + String getEmployeeLocatorId(User user) throws GrantDataException; + /** * Returns the latest update timestamp string. * @return the latest update timestamp string diff --git a/pass-grant-loader/pass-grant-data/src/main/resources/logback.xml b/pass-grant-loader/pass-grant-data/src/main/resources/logback.xml index 043c7d19..34d04098 100644 --- a/pass-grant-loader/pass-grant-data/src/main/resources/logback.xml +++ b/pass-grant-loader/pass-grant-data/src/main/resources/logback.xml @@ -26,4 +26,7 @@ + + + \ No newline at end of file diff --git a/pass-grant-loader/pass-grant-data/src/test/java/org/eclipse/pass/support/grant/data/DirectoryServiceUtilTest.java b/pass-grant-loader/pass-grant-data/src/test/java/org/eclipse/pass/support/grant/data/DirectoryServiceUtilTest.java deleted file mode 100644 index e70d1014..00000000 --- a/pass-grant-loader/pass-grant-data/src/test/java/org/eclipse/pass/support/grant/data/DirectoryServiceUtilTest.java +++ /dev/null @@ -1,85 +0,0 @@ -/* - * Copyright 2023 Johns Hopkins University - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.eclipse.pass.support.grant.data; - -import static org.eclipse.pass.support.grant.data.DirectoryServiceUtil.DIRECTORY_SERVICE_BASE_URL; -import static org.eclipse.pass.support.grant.data.DirectoryServiceUtil.DIRECTORY_SERVICE_CLIENT_ID; -import static org.eclipse.pass.support.grant.data.DirectoryServiceUtil.DIRECTORY_SERVICE_CLIENT_SECRET; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertNull; - -import java.io.IOException; -import java.util.Properties; - -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Disabled; -import org.junit.jupiter.api.Test; - - -/** - * This is a test class for a simple directory lookup service running at the endpoint specified by "serviceUrl" below - * the service type completes the URL, and the client id and client secret are supplied as headers. - *

- * values for serviceUrl, clientId and clientSecret, must be supplied below. - *

- * This test has been run against the running service with valid parameters and arguments supplied to the methods - - * this class has been - * cleaned up after successful testing. because of the simplicity and isolation of this class, it does not need to be - * tested - * every build - just when something about the service changes. so we ignore it for now. - *

- * To test, provide real connection parameter values, and a real kopkins id / employee id pair - * - * @author jrm - */ -@Disabled -public class DirectoryServiceUtilTest { - private DirectoryServiceUtil underTest; - - private final String validEeid = ""; //actual employee id - private final String validHopkinsId = ""; //actual matching hopkins id - - @BeforeEach - public void setup() { - final String serviceUrl = "https://the.service/url"; - final String clientId = "the-client-id"; - final String clientSecret = "the-client-secret"; - - Properties connectionProperties = new Properties(); - connectionProperties.setProperty(DIRECTORY_SERVICE_BASE_URL, serviceUrl); - connectionProperties.setProperty(DIRECTORY_SERVICE_CLIENT_ID, clientId); - connectionProperties.setProperty(DIRECTORY_SERVICE_CLIENT_SECRET, clientSecret); - underTest = new DirectoryServiceUtil(connectionProperties); - } - - @Test - public void testGetHopkinsId() throws java.io.IOException { - String result = underTest.getHopkinsIdForEmployeeId(validEeid); - assertEquals(validHopkinsId, result); - } - - @Test - public void testGetEmployeeId() throws java.io.IOException { - String result = underTest.getEmployeeIdForHopkinsId(validHopkinsId); - assertEquals(validEeid, result); - } - - @Test - public void testGetEmployeeIdIsNull() throws IOException { - String result = underTest.getEmployeeIdForHopkinsId("SomeBadValue"); - assertNull(result); - } -} diff --git a/pass-grant-loader/pass-grant-data/src/test/java/org/eclipse/pass/support/grant/data/JhuPassInitUpdaterIT.java b/pass-grant-loader/pass-grant-data/src/test/java/org/eclipse/pass/support/grant/data/JhuPassInitUpdaterIT.java index 20a3d876..6ecdbe66 100644 --- a/pass-grant-loader/pass-grant-data/src/test/java/org/eclipse/pass/support/grant/data/JhuPassInitUpdaterIT.java +++ b/pass-grant-loader/pass-grant-data/src/test/java/org/eclipse/pass/support/grant/data/JhuPassInitUpdaterIT.java @@ -33,11 +33,12 @@ import static org.eclipse.pass.support.grant.data.CoeusFieldNames.C_USER_EMAIL; import static org.eclipse.pass.support.grant.data.CoeusFieldNames.C_USER_EMPLOYEE_ID; import static org.eclipse.pass.support.grant.data.CoeusFieldNames.C_USER_FIRST_NAME; -import static org.eclipse.pass.support.grant.data.CoeusFieldNames.C_USER_HOPKINS_ID; import static org.eclipse.pass.support.grant.data.CoeusFieldNames.C_USER_INSTITUTIONAL_ID; import static org.eclipse.pass.support.grant.data.CoeusFieldNames.C_USER_LAST_NAME; import static org.eclipse.pass.support.grant.data.CoeusFieldNames.C_USER_MIDDLE_NAME; import static org.eclipse.pass.support.grant.data.DateTimeUtil.createZonedDateTime; +import static org.eclipse.pass.support.grant.data.JhuPassUpdater.EMPLOYEE_LOCATOR_ID; +import static org.eclipse.pass.support.grant.data.JhuPassUpdater.JHED_LOCATOR_ID; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertTrue; @@ -71,7 +72,6 @@ public class JhuPassInitUpdaterIT { {"2006-03-11 00:00:00.0", "2010-04-05 00:00:00.0", "2015-11-11 00:00:00.0"}; private final String[] userEmployeeId = {"30000000", "30000001", "30000002"}; private final String[] userInstitutionalId = {"amelon1", "aeinst1", "jjones1"}; - private final String[] userHopkinsId = {"RANDOM", "OMRNDA", "DRMONA"}; private final String[] userFirstName = {"Andrew", "Albert", "Junie"}; private final String[] userMiddleName = {"Smith", "Carnegie", "Beatrice"}; private final String[] userLastName = {"Melon", "Einstein", "Jones"}; @@ -82,13 +82,8 @@ public class JhuPassInitUpdaterIT { private final String grantIdPrefix = "johnshopkins.edu:grant:"; //private final String funderIdPrefix = "johnshopkins.edu:funder:"; - //private final String hopkinsidPrefix = "johnshopkins.edu:hopkinsid:"; - private final String employeeidPrefix = "johnshopkins.edu:employeeid:"; - //private final String jhedidPrefis = "johnshopkins.edu:jhed:"; private final PassClient passClient = PassClient.newInstance(); - private final JhuPassInitUpdater passUpdater = new JhuPassInitUpdater(passClient); - private final PassUpdateStatistics statistics = passUpdater.getStatistics(); @BeforeEach public void setup() throws IOException { @@ -103,7 +98,6 @@ public void setup() throws IOException { policy2.setDescription("MOO"); passClient.createObject(policy2); directFunderPolicyUriString = policy2.getId(); - } /** @@ -117,12 +111,14 @@ public void setup() throws IOException { */ @Test public void processInitGrantIT() throws IOException { + // GIVEN List> resultSet = new ArrayList<>(); //put in last iteration as existing record - PI is Einstein Map piRecord2 = makeRowMap(2, 1, "P"); resultSet.add(piRecord2); + JhuPassInitUpdater passUpdater = new JhuPassInitUpdater(); passUpdater.updatePass(resultSet, "grant"); PassClientSelector grantSelector = new PassClientSelector<>(Grant.class); @@ -132,11 +128,7 @@ public void processInitGrantIT() throws IOException { assertEquals(1, resultGrant.getTotal()); Grant passGrant = resultGrant.getObjects().get(0); - PassClientSelector userSelector = new PassClientSelector<>(User.class); - userSelector.setFilter(RSQL.hasMember("locatorIds", employeeidPrefix + userEmployeeId[1])); - PassClientResult resultUser = passClient.selectObjects(userSelector); - assertEquals(1, resultUser.getTotal()); - User userGrantPi = resultUser.getObjects().get(0); + User userGrantPi = getVerifiedUser(1); assertEquals(grantAwardNumber[2], passGrant.getAwardNumber()); assertEquals(AwardStatus.ACTIVE, passGrant.getAwardStatus()); @@ -149,10 +141,10 @@ public void processInitGrantIT() throws IOException { assertEquals(0, passGrant.getCoPis().size()); //check statistics - assertEquals(1, statistics.getGrantsCreated()); - assertEquals(1, statistics.getUsersCreated()); - assertEquals(1, statistics.getPisAdded()); - assertEquals(0, statistics.getCoPisAdded()); + assertEquals(1, passUpdater.getStatistics().getGrantsCreated()); + assertEquals(1, passUpdater.getStatistics().getUsersCreated()); + assertEquals(1, passUpdater.getStatistics().getPisAdded()); + assertEquals(0, passUpdater.getStatistics().getCoPisAdded()); //now simulate a complete pull from the Beginning of Time and adjust the stored grant //we add a new co-pi Jones in the "1" iteration, and change the pi to Einstein in the "2" iteration @@ -178,20 +170,9 @@ public void processInitGrantIT() throws IOException { assertEquals(1, resultGrant.getTotal()); Grant updatePassGrant = resultGrant.getObjects().get(0); - userSelector.setFilter(RSQL.hasMember("locatorIds", employeeidPrefix + userEmployeeId[0])); - resultUser = passClient.selectObjects(userSelector); - assertEquals(1, resultUser.getTotal()); - User user0 = resultUser.getObjects().get(0); - - userSelector.setFilter(RSQL.hasMember("locatorIds", employeeidPrefix + userEmployeeId[1])); - resultUser = passClient.selectObjects(userSelector); - assertEquals(1, resultUser.getTotal()); - User user1 = resultUser.getObjects().get(0); - - userSelector.setFilter(RSQL.hasMember("locatorIds", employeeidPrefix + userEmployeeId[2])); - resultUser = passClient.selectObjects(userSelector); - assertEquals(1, resultUser.getTotal()); - User user2 = resultUser.getObjects().get(0); + User user0 = getVerifiedUser(0); + User user1 = getVerifiedUser(1); + User user2 = getVerifiedUser(2); assertEquals(grantAwardNumber[0], updatePassGrant.getAwardNumber());//initial assertEquals(AwardStatus.ACTIVE, updatePassGrant.getAwardStatus()); @@ -206,6 +187,18 @@ public void processInitGrantIT() throws IOException { assertTrue(updatePassGrant.getCoPis().contains(user2));//Jones } + private User getVerifiedUser(int userIndex) throws IOException { + PassClientSelector userSelector = new PassClientSelector<>(User.class); + userSelector.setFilter(RSQL.hasMember("locatorIds", EMPLOYEE_LOCATOR_ID + userEmployeeId[userIndex])); + PassClientResult resultUser = passClient.selectObjects(userSelector); + assertEquals(1, resultUser.getTotal()); + User user = resultUser.getObjects().get(0); + assertEquals(2, user.getLocatorIds().size()); + assertEquals(EMPLOYEE_LOCATOR_ID + userEmployeeId[userIndex], user.getLocatorIds().get(0)); + assertEquals(JHED_LOCATOR_ID + userInstitutionalId[userIndex], user.getLocatorIds().get(1)); + return user; + } + /** * utility method to produce data as it would look coming from COEUS * @@ -235,7 +228,6 @@ private Map makeRowMap(int iteration, int user, String abbrRole) rowMap.put(C_USER_EMAIL, userEmail[user]); rowMap.put(C_USER_INSTITUTIONAL_ID, userInstitutionalId[user]); rowMap.put(C_USER_EMPLOYEE_ID, userEmployeeId[user]); - rowMap.put(C_USER_HOPKINS_ID, userHopkinsId[user]); rowMap.put(C_UPDATE_TIMESTAMP, grantUpdateTimestamp[iteration]); rowMap.put(C_ABBREVIATED_ROLE, abbrRole); diff --git a/pass-grant-loader/pass-grant-data/src/test/java/org/eclipse/pass/support/grant/data/JhuPassUpdaterIT.java b/pass-grant-loader/pass-grant-data/src/test/java/org/eclipse/pass/support/grant/data/JhuPassUpdaterIT.java index b2522b1e..ba824370 100644 --- a/pass-grant-loader/pass-grant-data/src/test/java/org/eclipse/pass/support/grant/data/JhuPassUpdaterIT.java +++ b/pass-grant-loader/pass-grant-data/src/test/java/org/eclipse/pass/support/grant/data/JhuPassUpdaterIT.java @@ -33,11 +33,12 @@ import static org.eclipse.pass.support.grant.data.CoeusFieldNames.C_USER_EMAIL; import static org.eclipse.pass.support.grant.data.CoeusFieldNames.C_USER_EMPLOYEE_ID; import static org.eclipse.pass.support.grant.data.CoeusFieldNames.C_USER_FIRST_NAME; -import static org.eclipse.pass.support.grant.data.CoeusFieldNames.C_USER_HOPKINS_ID; import static org.eclipse.pass.support.grant.data.CoeusFieldNames.C_USER_INSTITUTIONAL_ID; import static org.eclipse.pass.support.grant.data.CoeusFieldNames.C_USER_LAST_NAME; import static org.eclipse.pass.support.grant.data.CoeusFieldNames.C_USER_MIDDLE_NAME; import static org.eclipse.pass.support.grant.data.DateTimeUtil.createZonedDateTime; +import static org.eclipse.pass.support.grant.data.JhuPassUpdater.EMPLOYEE_LOCATOR_ID; +import static org.eclipse.pass.support.grant.data.JhuPassUpdater.JHED_LOCATOR_ID; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertTrue; @@ -60,38 +61,37 @@ public class JhuPassUpdaterIT { - private final String[] grantAwardNumber = {"B10000000", "B10000001", "B10000002"}; + private final String[] grantAwardNumber = {"B10000000", "B10000001", "B10000002", "B10000003", "B10000004"}; private final String[] grantLocalKey = - {"10000001", "10000001", "10000001"}; //all the same, different from other ITs tho + {"10000001", "10000001", "10000001", "10000002", "10000003"}; //all the same, different from other ITs tho private final String[] grantProjectName = - {"Stupendous Research Project I", "Stupendous Research Project II", "Stupendous Research ProjectIII"}; - private final String[] grantAwardDate = {"01/01/1999", "01/01/2001", "01/01/2003"}; + {"Stupendous Research Project I", "Stupendous Research Project II", "Stupendous Research ProjectIII", + "Stupendous Research ProjectIV", "Stupendous Research ProjectV"}; + private final String[] grantAwardDate = {"01/01/1999", "01/01/2001", "01/01/2003", "01/01/2004", "01/01/2005"}; + //these appear to ge the same for all awards private final String[] grantStartDate = - {"07/01/2000", "07/01/2000", "07/01/2000"}; //these appear to ge the same for all awards + {"07/01/2000", "07/01/2000", "07/01/2000", "07/01/2000", "07/01/2000"}; + //these seem to be the same for all awards private final String[] grantEndDate = - {"06/30/2004", "06/30/2004", "06/30/2004"};//these seem to be the same for all awards + {"06/30/2004", "06/30/2004", "06/30/2004", "06/30/2004", "06/30/2004"}; private final String[] grantUpdateTimestamp = - {"2006-03-11 00:00:00.0", "2010-04-05 00:00:00.0", "2015-11-11 00:00:00.0"}; - private final String[] userEmployeeId = {"31000000", "31000001", "31000002"}; - private final String[] userInstitutionalId = {"arecko1", "sclass1", "jgunn1"}; - private final String[] userHopkinsId = {"DOMNAR", "NROAD", "ROMAND"}; - private final String[] userFirstName = {"Amanda", "Skip", "Janie"}; - private final String[] userMiddleName = {"Bea", "Avery", "Gotta"}; - private final String[] userLastName = {"Reckondwith", "Class", "Gunn"}; - private final String[] userEmail = {"arecko1@jhu.edu", "sclass1@jhu.edu", "jgunn1@jhu.edu"}; + {"2006-03-11 00:00:00.0", "2010-04-05 00:00:00.0", "2015-11-11 00:00:00.0", "2016-11-11 00:00:00.0", + "2016-12-11 00:00:00.0"}; + private final String[] userEmployeeId = {"31000000", "31000001", "31000002", "31000003", "31000004"}; + private final String[] userInstitutionalId = {"arecko1", "sclass1", "jgunn1", "jdoe1", "jdoe2"}; + private final String[] userFirstName = {"Amanda", "Skip", "Janie", "John", "James"}; + private final String[] userMiddleName = {"Bea", "Avery", "Gotta", "Nobody", ""}; + private final String[] userLastName = {"Reckondwith", "Class", "Gunn", "Doe1", "Doe2"}; + private final String[] userEmail = {"arecko1@jhu.edu", "sclass1@jhu.edu", "jgunn1@jhu.edu", "jdoe1@jhu.edu", + "jdoe2@jhu.edu"}; private String primaryFunderPolicyUriString; private String directFunderPolicyUriString; private final String grantIdPrefix = "johnshopkins.edu:grant:"; //private final String funderIdPrefix = "johnshopkins.edu:funder:"; - //private final String hopkinsidPrefix = "johnshopkins.edu:hopkinsid:"; - private final String employeeidPrefix = "johnshopkins.edu:employeeid:"; - //String jhedidPrefis = "johnshopkins.edu:jhed:"; private final PassClient passClient = PassClient.newInstance(); - private final JhuPassUpdater passUpdater = new JhuPassUpdater(passClient); - private final PassUpdateStatistics statistics = passUpdater.getStatistics(); @BeforeEach public void setup() throws IOException { @@ -110,7 +110,7 @@ public void setup() throws IOException { /** * we put an initial award for a grant into PASS, then simulate a pull of all subsequent records - * + *

* We expect to see some fields retained from the initial award, and others updated. The most * interesting fields are the investigator fields: all CO-PIs ever on the grant should stay on the * co-pi field throughout iterations. If a PI is changed, they should appear on the CO-PI field @@ -118,17 +118,21 @@ public void setup() throws IOException { */ @Test public void processGrantIT() throws IOException { - List> resultSet = new ArrayList<>(); - + // GIVEN //put in initial iteration as a correct existing record - PI is Reckondwith, Co-pi is Class Map piRecord0 = makeRowMap(0, 0, "P"); Map coPiRecord0 = makeRowMap(0, 1, "C"); + List> resultSet = new ArrayList<>(); resultSet.add(piRecord0); resultSet.add(coPiRecord0); + JhuPassUpdater passUpdater = new JhuPassUpdater(); + + // WHEN passUpdater.updatePass(resultSet, "grant"); + // THEN PassClientSelector grantSelector = new PassClientSelector<>(Grant.class); grantSelector.setFilter(RSQL.equals("localKey", grantIdPrefix + grantLocalKey[2])); grantSelector.setInclude("primaryFunder", "directFunder", "pi", "coPis"); @@ -136,17 +140,8 @@ public void processGrantIT() throws IOException { assertEquals(1, resultGrant.getTotal()); Grant passGrant = resultGrant.getObjects().get(0); - PassClientSelector user0Selector = new PassClientSelector<>(User.class); - user0Selector.setFilter(RSQL.hasMember("locatorIds", employeeidPrefix + userEmployeeId[0])); - PassClientResult resultUser0 = passClient.selectObjects(user0Selector); - assertEquals(1, resultUser0.getTotal()); - User user0 = resultUser0.getObjects().get(0); - - PassClientSelector user1Selector = new PassClientSelector<>(User.class); - user1Selector.setFilter(RSQL.hasMember("locatorIds", employeeidPrefix + userEmployeeId[1])); - PassClientResult resultUser1 = passClient.selectObjects(user1Selector); - assertEquals(1, resultUser1.getTotal()); - User user1 = resultUser1.getObjects().get(0); + User user0 = getVerifiedUser(0); + User user1 = getVerifiedUser(1); assertEquals(grantAwardNumber[0], passGrant.getAwardNumber()); assertEquals(AwardStatus.ACTIVE, passGrant.getAwardStatus()); @@ -161,15 +156,15 @@ public void processGrantIT() throws IOException { assertEquals(user1, passGrant.getCoPis().get(0)); //check statistics - assertEquals(1, statistics.getGrantsCreated()); - assertEquals(2, statistics.getUsersCreated()); - assertEquals(1, statistics.getPisAdded()); - assertEquals(1, statistics.getCoPisAdded()); + assertEquals(1, passUpdater.getStatistics().getGrantsCreated()); + assertEquals(2, passUpdater.getStatistics().getUsersCreated()); + assertEquals(1, passUpdater.getStatistics().getPisAdded()); + assertEquals(1, passUpdater.getStatistics().getCoPisAdded()); + // WHEN //now simulate an incremental pull since the initial, adjust the stored grant //we add a new co-pi Jones in the "1" iteration, and change the pi to Einstein in the "2" iteration //we drop co-pi jones in the last iteration - Map piRecord1 = makeRowMap(1, 0, "P"); Map coPiRecord1 = makeRowMap(1, 1, "C"); Map newCoPiRecord1 = makeRowMap(1, 2, "C"); @@ -184,15 +179,12 @@ public void processGrantIT() throws IOException { passUpdater.updatePass(resultSet, "grant"); + // THEN resultGrant = passClient.selectObjects(grantSelector); assertEquals(1, resultGrant.getTotal()); Grant updatePassGrant = resultGrant.getObjects().get(0); - PassClientSelector user2Selector = new PassClientSelector<>(User.class); - user2Selector.setFilter(RSQL.hasMember("locatorIds", employeeidPrefix + userEmployeeId[2])); - PassClientResult resultUser2 = passClient.selectObjects(user2Selector); - assertEquals(1, resultUser2.getTotal()); - User user2 = resultUser2.getObjects().get(0); + User user2 = getVerifiedUser(2); assertEquals(grantAwardNumber[0], updatePassGrant.getAwardNumber());//initial assertEquals(AwardStatus.ACTIVE, updatePassGrant.getAwardStatus()); @@ -208,6 +200,102 @@ public void processGrantIT() throws IOException { assertTrue(updatePassGrant.getCoPis().contains(user2));//Gunn } + @Test + public void processGrantIT_UpdateUserLocatorsJhed() throws IOException { + // GIVEN + Map piRecord0 = makeRowMap(4, 4, "P"); + + List> resultSet = new ArrayList<>(); + resultSet.add(piRecord0); + + JhuPassUpdater passUpdater = new JhuPassUpdater(); + + // WHEN + passUpdater.updatePass(resultSet, "grant"); + + // THEN + PassClientSelector grantSelector = new PassClientSelector<>(Grant.class); + grantSelector.setFilter(RSQL.equals("localKey", grantIdPrefix + grantLocalKey[4])); + grantSelector.setInclude("primaryFunder", "directFunder", "pi", "coPis"); + PassClientResult resultGrant = passClient.selectObjects(grantSelector); + assertEquals(1, resultGrant.getTotal()); + Grant passGrant = resultGrant.getObjects().get(0); + + PassClientSelector user2Selector = new PassClientSelector<>(User.class); + user2Selector.setFilter(RSQL.hasMember("locatorIds", EMPLOYEE_LOCATOR_ID + userEmployeeId[4])); + PassClientResult resultUser2 = passClient.selectObjects(user2Selector); + assertEquals(1, resultUser2.getTotal()); + User addedUser = resultUser2.getObjects().get(0); + assertEquals(2, addedUser.getLocatorIds().size()); + assertEquals(EMPLOYEE_LOCATOR_ID + userEmployeeId[4], addedUser.getLocatorIds().get(0)); + assertEquals(JHED_LOCATOR_ID + userInstitutionalId[4], addedUser.getLocatorIds().get(1)); + + assertEquals(grantAwardNumber[4], passGrant.getAwardNumber()); + assertEquals(AwardStatus.ACTIVE, passGrant.getAwardStatus()); + assertEquals(grantIdPrefix + grantLocalKey[4], passGrant.getLocalKey()); + assertEquals(grantProjectName[4], passGrant.getProjectName()); + assertEquals(createZonedDateTime(grantAwardDate[4]), passGrant.getAwardDate()); + assertEquals(createZonedDateTime(grantStartDate[4]), passGrant.getStartDate()); + assertEquals(createZonedDateTime(grantEndDate[4]), passGrant.getEndDate()); + assertEquals(grantUpdateTimestamp[4], passUpdater.getLatestUpdate());//latest + assertEquals(addedUser, passGrant.getPi()); + assertEquals(0, passGrant.getCoPis().size()); + + //check statistics + assertEquals(1, passUpdater.getStatistics().getGrantsCreated()); + assertEquals(1, passUpdater.getStatistics().getUsersCreated()); + assertEquals(1, passUpdater.getStatistics().getPisAdded()); + assertEquals(0, passUpdater.getStatistics().getCoPisAdded()); + + // WHEN + // JHED ID and Hopkins ID update from coeus + Map piRecordUpdate = makeRowMap(4, 4, "P"); + piRecordUpdate.put(C_USER_INSTITUTIONAL_ID, "newjdoe1jhed"); + + //add in everything since the initial pull + resultSet.clear(); + resultSet.add(piRecordUpdate); + + passUpdater.updatePass(resultSet, "grant"); + + // THEN + resultGrant = passClient.selectObjects(grantSelector); + assertEquals(1, resultGrant.getTotal()); + Grant updatePassGrant = resultGrant.getObjects().get(0); + + PassClientSelector updatedUserSelector = new PassClientSelector<>(User.class); + updatedUserSelector.setFilter(RSQL.hasMember("locatorIds", EMPLOYEE_LOCATOR_ID + userEmployeeId[4])); + PassClientResult resultUpdateUser = passClient.selectObjects(updatedUserSelector); + assertEquals(1, resultUpdateUser.getTotal()); + User updatedUser = resultUpdateUser.getObjects().get(0); + assertEquals(2, updatedUser.getLocatorIds().size()); + assertEquals(EMPLOYEE_LOCATOR_ID + userEmployeeId[4], updatedUser.getLocatorIds().get(0)); + assertEquals(JHED_LOCATOR_ID + "newjdoe1jhed", updatedUser.getLocatorIds().get(1)); + + assertEquals(grantAwardNumber[4], updatePassGrant.getAwardNumber());//initial + assertEquals(AwardStatus.ACTIVE, updatePassGrant.getAwardStatus()); + assertEquals(grantIdPrefix + grantLocalKey[4], updatePassGrant.getLocalKey()); + assertEquals(grantProjectName[4], updatePassGrant.getProjectName());//initial + assertEquals(createZonedDateTime(grantAwardDate[4]), updatePassGrant.getAwardDate());//initial + assertEquals(createZonedDateTime(grantStartDate[4]), updatePassGrant.getStartDate());//initial + assertEquals(createZonedDateTime(grantEndDate[4]), updatePassGrant.getEndDate());//latest + assertEquals(grantUpdateTimestamp[4], passUpdater.getLatestUpdate());//latest + assertEquals(updatedUser, updatePassGrant.getPi());//Class + assertEquals(0, updatePassGrant.getCoPis().size()); + } + + private User getVerifiedUser(int userIndex) throws IOException { + PassClientSelector userSelector = new PassClientSelector<>(User.class); + userSelector.setFilter(RSQL.hasMember("locatorIds", EMPLOYEE_LOCATOR_ID + userEmployeeId[userIndex])); + PassClientResult resultUser = passClient.selectObjects(userSelector); + assertEquals(1, resultUser.getTotal()); + User user = resultUser.getObjects().get(0); + assertEquals(2, user.getLocatorIds().size()); + assertEquals(EMPLOYEE_LOCATOR_ID + userEmployeeId[userIndex], user.getLocatorIds().get(0)); + assertEquals(JHED_LOCATOR_ID + userInstitutionalId[userIndex], user.getLocatorIds().get(1)); + return user; + } + /** * utility method to produce data as it would look coming from COEUS * @@ -237,7 +325,6 @@ private Map makeRowMap(int iteration, int user, String abbrRole) rowMap.put(C_USER_EMAIL, userEmail[user]); rowMap.put(C_USER_INSTITUTIONAL_ID, userInstitutionalId[user]); rowMap.put(C_USER_EMPLOYEE_ID, userEmployeeId[user]); - rowMap.put(C_USER_HOPKINS_ID, userHopkinsId[user]); rowMap.put(C_UPDATE_TIMESTAMP, grantUpdateTimestamp[iteration]); rowMap.put(C_ABBREVIATED_ROLE, abbrRole); diff --git a/pass-grant-loader/pass-grant-data/src/test/java/org/eclipse/pass/support/grant/data/JhuPassUpdaterTest.java b/pass-grant-loader/pass-grant-data/src/test/java/org/eclipse/pass/support/grant/data/JhuPassUpdaterTest.java index a1f90e24..8f0d5149 100644 --- a/pass-grant-loader/pass-grant-data/src/test/java/org/eclipse/pass/support/grant/data/JhuPassUpdaterTest.java +++ b/pass-grant-loader/pass-grant-data/src/test/java/org/eclipse/pass/support/grant/data/JhuPassUpdaterTest.java @@ -27,6 +27,7 @@ import java.util.List; import java.util.Map; +import org.apache.commons.lang3.reflect.FieldUtils; import org.eclipse.pass.support.client.PassClient; import org.eclipse.pass.support.client.PassClientResult; import org.eclipse.pass.support.client.model.AwardStatus; @@ -34,6 +35,7 @@ import org.eclipse.pass.support.client.model.Grant; import org.eclipse.pass.support.client.model.PassEntity; import org.eclipse.pass.support.client.model.User; +import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.Mock; @@ -50,8 +52,16 @@ public class JhuPassUpdaterTest { @Mock private PassClient passClientMock; + @BeforeEach + public void beforeTest() { + System.setProperty("pass.core.url", "http://test-host"); + System.setProperty("pass.core.user", "test-user"); + System.setProperty("pass.core.password", "test-password"); + } + + @SuppressWarnings("unchecked") @Test - public void testUpdatePassGrant_Success_NewGrant() throws IOException { + public void testUpdatePassGrant_Success_NewGrant() throws IOException, IllegalAccessException { List> resultSet = buildTestInputResultSet(); preparePassClientMockCallsGrantRelations(); @@ -63,18 +73,21 @@ public void testUpdatePassGrant_Success_NewGrant() throws IOException { passClientSelector.getFilter().equals( "localKey=='johnshopkins.edu:grant:8675309'"))); - JhuPassUpdater passUpdater = new JhuPassUpdater(passClientMock); + JhuPassUpdater passUpdater = new JhuPassUpdater(); + FieldUtils.writeField(passUpdater, "passClient", passClientMock, true); passUpdater.updatePass(resultSet, "grant"); Map grantMap = passUpdater.getGrantResultMap(); assertEquals(1, grantMap.size()); Grant grant = grantMap.get("8675309"); assertEquals(1, grant.getCoPis().size()); - assertEquals(2, passUpdater.getFunderMap().size()); - assertEquals(grant.getDirectFunder(), passUpdater.getFunderMap().get("000029282")); - assertEquals(grant.getPrimaryFunder(), passUpdater.getFunderMap().get("8675309")); - assertEquals(grant.getPi(), passUpdater.getUserMap().get("0000333")); - assertEquals(grant.getCoPis().get(0), passUpdater.getUserMap().get("0000222")); + Map funderMap = (Map) FieldUtils.readField(passUpdater, "funderMap", true); + assertEquals(2, funderMap.size()); + assertEquals(grant.getDirectFunder(), funderMap.get("000029282")); + assertEquals(grant.getPrimaryFunder(), funderMap.get("8675309")); + Map userMap = (Map) FieldUtils.readField(passUpdater, "userMap", true); + assertEquals(grant.getPi(), userMap.get("0000333")); + assertEquals(grant.getCoPis().get(0), userMap.get("0000222")); assertEquals("12345678", grant.getAwardNumber()); assertEquals(AwardStatus.ACTIVE, grant.getAwardStatus()); @@ -89,7 +102,7 @@ public void testUpdatePassGrant_Success_NewGrant() throws IOException { } @Test - public void testUpdatePassGrant_Success_SkipDuplicateGrantInPass() throws IOException { + public void testUpdatePassGrant_Success_SkipDuplicateGrantInPass() throws IOException, IllegalAccessException { List> resultSet = buildTestInputResultSet(); preparePassClientMockCallsGrantRelations(); @@ -103,7 +116,8 @@ public void testUpdatePassGrant_Success_SkipDuplicateGrantInPass() throws IOExce passClientSelector.getFilter().equals( "localKey=='johnshopkins.edu:grant:8675309'"))); - JhuPassUpdater passUpdater = new JhuPassUpdater(passClientMock); + JhuPassUpdater passUpdater = new JhuPassUpdater(); + FieldUtils.writeField(passUpdater, "passClient", passClientMock, true); passUpdater.updatePass(resultSet, "grant"); Map grantMap = passUpdater.getGrantResultMap(); @@ -233,18 +247,16 @@ public void testUserBuilding() { rowMap.put(CoeusFieldNames.C_USER_EMAIL, "mlartz3@jhu.edu"); rowMap.put(CoeusFieldNames.C_USER_INSTITUTIONAL_ID, "MLARTZ5"); rowMap.put(CoeusFieldNames.C_USER_EMPLOYEE_ID, "0000222"); - rowMap.put(CoeusFieldNames.C_USER_HOPKINS_ID, "A1A1A1"); rowMap.put(CoeusFieldNames.C_UPDATE_TIMESTAMP, "2018-01-01 0:00:00.0"); - JhuPassUpdater passUpdater = new JhuPassUpdater(passClientMock); + JhuPassUpdater passUpdater = new JhuPassUpdater(); User newUser = passUpdater.buildUser(rowMap); //unusual fields assertEquals("Marsha Lartz", newUser.getDisplayName()); //test ids assertEquals("johnshopkins.edu:employeeid:0000222", newUser.getLocatorIds().get(0)); - assertEquals("johnshopkins.edu:unique-id:A1A1A1", newUser.getLocatorIds().get(1)); - assertEquals("johnshopkins.edu:eppn:mlartz5", newUser.getLocatorIds().get(2)); + assertEquals("johnshopkins.edu:eppn:mlartz5", newUser.getLocatorIds().get(1)); } @Test @@ -254,7 +266,7 @@ public void testPrimaryFunderBuilding() { rowMap.put(CoeusFieldNames.C_PRIMARY_FUNDER_LOCAL_KEY, "8675309"); rowMap.put(CoeusFieldNames.C_PRIMARY_FUNDER_POLICY, "policy1"); - JhuPassUpdater passUpdater = new JhuPassUpdater(passClientMock); + JhuPassUpdater passUpdater = new JhuPassUpdater(); Funder newFunder = passUpdater.buildPrimaryFunder(rowMap); assertEquals("Funder Name", newFunder.getName()); @@ -271,7 +283,7 @@ public void testUpdatePassUser_Fail_ModeCheck() { rowMap.put(CoeusFieldNames.C_GRANT_LOCAL_KEY, CoeusFieldNames.C_GRANT_LOCAL_KEY); grantResultSet.add(rowMap); - JhuPassUpdater passUpdater = new JhuPassUpdater(passClientMock); + JhuPassUpdater passUpdater = new JhuPassUpdater(); passUpdater.updatePass(grantResultSet, "user"); }); @@ -285,7 +297,7 @@ public void testUpdatePassGrant_Fail_ModeCheck() { rowMap.put(CoeusFieldNames.C_USER_EMPLOYEE_ID, CoeusFieldNames.C_USER_EMPLOYEE_ID); userResultSet.add(rowMap); - JhuPassUpdater passUpdater = new JhuPassUpdater(passClientMock); + JhuPassUpdater passUpdater = new JhuPassUpdater(); passUpdater.updatePass(userResultSet, "grant"); }); @@ -299,7 +311,7 @@ public void testUpdatePassFunder_Fail_ModeCheck() { rowMap.put(CoeusFieldNames.C_USER_EMPLOYEE_ID, CoeusFieldNames.C_USER_EMPLOYEE_ID); userResultSet.add(rowMap); - JhuPassUpdater passUpdater = new JhuPassUpdater(passClientMock); + JhuPassUpdater passUpdater = new JhuPassUpdater(); passUpdater.updatePass(userResultSet, "funder"); }); diff --git a/pass-grant-loader/pass-grant-data/src/test/resources/logback-test.xml b/pass-grant-loader/pass-grant-data/src/test/resources/logback-test.xml index e57e471c..df310da3 100644 --- a/pass-grant-loader/pass-grant-data/src/test/resources/logback-test.xml +++ b/pass-grant-loader/pass-grant-data/src/test/resources/logback-test.xml @@ -26,7 +26,7 @@ - + \ No newline at end of file