Skip to content

Commit

Permalink
Certification module tests passing.
Browse files Browse the repository at this point in the history
  • Loading branch information
mederly committed Apr 3, 2017
1 parent 974c724 commit 0def79e
Show file tree
Hide file tree
Showing 16 changed files with 219 additions and 138 deletions.
Expand Up @@ -72,7 +72,7 @@ public CertCaseDto(AccessCertificationCaseType _case, PageBase page, Task task,
}
List<String> names = new ArrayList<>();
// TODO show by work items
for (ObjectReferenceType reviewerRef : CertCampaignTypeUtil.getReviewers(_case)) {
for (ObjectReferenceType reviewerRef : CertCampaignTypeUtil.getCurrentReviewers(_case)) {
// TODO optimize - don't resolve reviewers twice
PrismObject<UserType> reviewerObject = WebModelServiceUtils.resolveReferenceRaw(reviewerRef, page, task, result);
if (reviewerObject != null) {
Expand Down
Expand Up @@ -81,7 +81,7 @@ public Iterator<CertDecisionDto> internalIterator(long first, long count) {
SelectorOptions.createCollection(GetOperationOptions.createResolveNames());

AccessCertificationService acs = getPage().getCertificationService();
List<AccessCertificationCaseType> caseList = acs.searchDecisionsToReview(caseQuery, notDecidedOnly, resolveNames, task, result);
List<AccessCertificationCaseType> caseList = acs.searchOpenWorkItems(caseQuery, notDecidedOnly, resolveNames, task, result);

for (AccessCertificationCaseType _case : caseList) {
getAvailableData().add(new CertDecisionDto(_case, getPage()));
Expand Down Expand Up @@ -117,7 +117,7 @@ protected int internalSize() {
AccessCertificationService acs = getPage().getCertificationService();
ObjectQuery query = getQuery().clone();
query.setPaging(null); // when counting decisions we need to exclude offset+size (and sorting info is irrelevant)
List<AccessCertificationCaseType> caseList = acs.searchDecisionsToReview(query, notDecidedOnly, null, task, result);
List<AccessCertificationCaseType> caseList = acs.searchOpenWorkItems(query, notDecidedOnly, null, task, result);
count = caseList.size();
} catch (Exception ex) {
result.recordFatalError("Couldn't count objects.", ex);
Expand Down
Expand Up @@ -258,7 +258,11 @@ private PrismValue toPrismValue(ItemDelta<?,?> currentDelta, Object v) {
} else if (definition instanceof PrismContainerDefinition) {
return ((Containerable) v).asPrismContainerValue();
} else if (definition instanceof PrismReferenceDefinition) {
throw new IllegalStateException("Using real value for reference deltas is not supported: " + v);
if (v instanceof Referencable) {
return ((Referencable) v).asReferenceValue();
} else {
throw new IllegalStateException("Expected Referencable, got: " + v);
}
} else {
throw new IllegalStateException("Unsupported definition type: " + definition);
}
Expand Down
Expand Up @@ -167,12 +167,14 @@ public static int getActiveCases(List<AccessCertificationCaseType> caseList, int
// "no reviewers" cases are treated as answered, because no answer can be provided
public static int getUnansweredCases(List<AccessCertificationCaseType> caseList, int campaignStageNumber, AccessCertificationCampaignStateType state) {
int unansweredCases = 0;
if (state == AccessCertificationCampaignStateType.IN_REMEDIATION || state == AccessCertificationCampaignStateType.CLOSED) {
campaignStageNumber = campaignStageNumber - 1; // move to last campaign state
}
for (AccessCertificationCaseType aCase : caseList) {
for (AccessCertificationWorkItemType workItem : aCase.getWorkItem()) {
if (workItem.getStageNumber() != campaignStageNumber) {
continue;
}
if (workItem.getClosedTimestamp() == null && (workItem.getResponse() == null || workItem.getResponse() == NO_RESPONSE)) {
if (workItem.getStageNumber() == campaignStageNumber
&& workItem.getClosedTimestamp() == null
&& (workItem.getResponse() == null || workItem.getResponse() == NO_RESPONSE)) {
unansweredCases++; // TODO what about delegations?
break;
}
Expand Down Expand Up @@ -312,6 +314,13 @@ public static ObjectQuery createCasesForCampaignQuery(String campaignOid, PrismC
.build();
}

public static ObjectQuery createWorkItemsForCampaignQuery(String campaignOid, PrismContext prismContext) throws SchemaException {
return QueryBuilder.queryFor(AccessCertificationWorkItemType.class, prismContext)
.exists(PrismConstants.T_PARENT)
.ownerId(campaignOid)
.build();
}

public static AccessCertificationCaseStageOutcomeType getStageOutcome(AccessCertificationCaseType aCase, int stageNumber) {
for (AccessCertificationCaseStageOutcomeType outcome : aCase.getCompletedStageOutcome()) {
if (outcome.getStageNumber() == stageNumber) {
Expand All @@ -331,8 +340,10 @@ public static List<AccessCertificationResponseType> getOutcomesToStopOn(List<Acc
}

// useful e.g. for tests
public static Set<ObjectReferenceType> getReviewers(AccessCertificationCaseType aCase) {
public static Set<ObjectReferenceType> getCurrentReviewers(AccessCertificationCaseType aCase) {
return aCase.getWorkItem().stream()
// TODO check also with campaign stage?
.filter(wi -> wi.getStageNumber() == aCase.getCurrentStageNumber() && wi.getClosedTimestamp() == null)
.flatMap(wi -> wi.getReviewerRef().stream())
.collect(Collectors.toSet());
}
Expand All @@ -348,4 +359,19 @@ public static AccessCertificationCaseType getCase(AccessCertificationWorkItemTyp
}
return ((PrismContainerValue<AccessCertificationCaseType>) parentParent).asContainerable();
}

public static AccessCertificationCampaignType getCampaign(AccessCertificationCaseType aCase) {
@SuppressWarnings({"unchecked", "raw"})
PrismContainer<AccessCertificationCaseType> caseContainer = (PrismContainer<AccessCertificationCaseType>) aCase.asPrismContainerValue().getParent();
if (caseContainer == null) {
return null;
}
@SuppressWarnings({"unchecked", "raw"})
PrismContainerValue<AccessCertificationCampaignType> campaignValue = (PrismContainerValue<AccessCertificationCampaignType>) caseContainer.getParent();
if (campaignValue == null) {
return null;
}
PrismObject<AccessCertificationCampaignType> campaign = (PrismObject<AccessCertificationCampaignType>) campaignValue.getParent();
return campaign != null ? campaign.asObjectable() : null;
}
}
Expand Up @@ -54,6 +54,7 @@
import javax.xml.namespace.QName;
import java.util.*;

import static com.evolveum.midpoint.schema.util.ObjectTypeUtil.toShortString;
import static com.evolveum.midpoint.xml.ns._public.common.common_3.AccessCertificationCampaignType.F_CASE;
import static com.evolveum.midpoint.xml.ns._public.common.common_3.AccessCertificationCaseType.*;

Expand All @@ -75,41 +76,33 @@ public class AccCertCaseOperationsHelper {
@Autowired private AccCertUpdateHelper updateHelper;
@Autowired private Clock clock;

void recordDecision(AccessCertificationCampaignType campaign, long caseId, long workItemId,
AccessCertificationResponseType response,
String comment, Task task, OperationResult result) throws SecurityViolationException, ObjectNotFoundException,
SchemaException, ObjectAlreadyExistsException {
String campaignOid = campaign.getOid();

if (!AccessCertificationCampaignStateType.IN_REVIEW_STAGE.equals(campaign.getState())) {
throw new IllegalStateException("Campaign is not in review stage; its state is " + campaign.getState());
}

void recordDecision(String campaignOid, long caseId, long workItemId,
AccessCertificationResponseType response, String comment, Task task, OperationResult result)
throws SecurityViolationException, ObjectNotFoundException, SchemaException, ObjectAlreadyExistsException {
AccessCertificationCaseType _case = queryHelper.getCase(campaignOid, caseId, task, result);
if (_case == null) {
throw new ObjectNotFoundException("Case " + caseId + " was not found in campaign " + ObjectTypeUtil.toShortString(campaign));
throw new ObjectNotFoundException("Case " + caseId + " was not found in campaign " + campaignOid);
}
AccessCertificationCampaignType campaign = CertCampaignTypeUtil.getCampaign(_case);
if (campaign == null) {
throw new IllegalStateException("No owning campaign present in case " + _case);
}
AccessCertificationWorkItemType workItem = CertCampaignTypeUtil.findWorkItem(_case, workItemId);
if (workItem == null) {
throw new ObjectNotFoundException("Work item " + workItemId + " was not found in campaign " + ObjectTypeUtil.toShortString(campaign) + ", case " + caseId);
throw new ObjectNotFoundException("Work item " + workItemId + " was not found in campaign " + toShortString(campaign) + ", case " + caseId);
}

ObjectReferenceType responderRef = ObjectTypeUtil.createObjectRef(securityEnforcer.getPrincipal().getUser());
XMLGregorianCalendar now = clock.currentTimeXMLGregorianCalendar();
ItemPath workItemPath = new ItemPath(
new NameItemPathSegment(F_CASE),
new IdItemPathSegment(caseId),
new NameItemPathSegment(AccessCertificationCaseType.F_WORK_ITEM),
new IdItemPathSegment(workItemId));
Collection<ItemDelta<?,?>> deltaList = new ArrayList<>();
deltaList.addAll(DeltaBuilder.deltaFor(AccessCertificationCampaignType.class, prismContext)
ItemPath workItemPath = new ItemPath(F_CASE, caseId, F_WORK_ITEM, workItemId);
Collection<ItemDelta<?,?>> deltaList = DeltaBuilder.deltaFor(AccessCertificationCampaignType.class, prismContext)
.item(workItemPath.subPath(AccessCertificationWorkItemType.F_RESPONSE)).replace(response)
.item(workItemPath.subPath(AccessCertificationWorkItemType.F_COMMENT)).replace(comment)
.item(workItemPath.subPath(AccessCertificationWorkItemType.F_TIMESTAMP)).replace(now)
.item(workItemPath.subPath(AccessCertificationWorkItemType.F_RESPONDER_REF)).replace(responderRef)
.asItemDeltas());
.asItemDeltas();

ItemDelta.applyTo(deltaList, _case.asPrismContainerValue());
ItemDelta.applyTo(deltaList, campaign.asPrismContainerValue());

AccessCertificationResponseType newCurrentOutcome = computationHelper.computeOutcomeForStage(_case, campaign, campaign.getStageNumber());
if (!ObjectUtils.equals(newCurrentOutcome, _case.getCurrentStageOutcome())) {
Expand Down Expand Up @@ -142,7 +135,7 @@ <F extends FocusType> List<ItemDelta<?,?>> getDeltasToCreateCases(

final List<ItemDelta<?,?>> rv = new ArrayList<>();

final String campaignShortName = ObjectTypeUtil.toShortString(campaign);
final String campaignShortName = toShortString(campaign);

final AccessCertificationScopeType scope = campaign.getScopeDefinition();
LOGGER.trace("Creating cases for scope {} in campaign {}", scope, campaignShortName);
Expand Down Expand Up @@ -194,7 +187,7 @@ <F extends FocusType> List<ItemDelta<?,?>> getDeltasToCreateCases(
caseList.addAll(handler.createCasesForObject(object, campaign, task, parentResult));
} catch (ExpressionEvaluationException|ObjectNotFoundException|SchemaException e) {
// TODO process the exception more intelligently
throw new SystemException("Cannot create certification case for object " + ObjectTypeUtil.toShortString(object.asObjectable()) + ": " + e.getMessage(), e);
throw new SystemException("Cannot create certification case for object " + toShortString(object.asObjectable()) + ": " + e.getMessage(), e);
}
return true;
};
Expand Down Expand Up @@ -243,7 +236,7 @@ private List<AccessCertificationWorkItemType> createWorkItems(List<ObjectReferen
List<ItemDelta<?,?>> getDeltasToAdvanceCases(AccessCertificationCampaignType campaign, AccessCertificationStageType stage, Task task, OperationResult result)
throws SchemaException, ObjectAlreadyExistsException, ObjectNotFoundException {

LOGGER.trace("Advancing reviewers and timestamps for cases in {}", ObjectTypeUtil.toShortString(campaign));
LOGGER.trace("Advancing reviewers and timestamps for cases in {}", toShortString(campaign));
List<AccessCertificationCaseType> caseList = queryHelper.searchCases(campaign.getOid(), null, null, result);
List<ItemDelta<?,?>> rv = new ArrayList<>(caseList.size());

Expand All @@ -266,7 +259,7 @@ List<ItemDelta<?,?>> getDeltasToAdvanceCases(AccessCertificationCampaignType cam
AccessCertificationResponseType currentOutcome = computationHelper.computeOutcomeForStage(_case, campaign, stageToBe);
AccessCertificationResponseType overallOutcome = computationHelper.computeOverallOutcome(_case, campaign, currentOutcome);
rv.addAll(DeltaBuilder.deltaFor(AccessCertificationCampaignType.class, prismContext)
.item(F_CASE, caseId, F_WORK_ITEM).add(workItems)
.item(F_CASE, caseId, F_WORK_ITEM).add(PrismContainerValue.toPcvList(workItems))
.item(F_CASE, caseId, F_CURRENT_REVIEW_REQUESTED_TIMESTAMP).replace(stage.getStart())
.item(F_CASE, caseId, F_CURRENT_REVIEW_DEADLINE).replace(stage.getDeadline())
.item(F_CASE, caseId, F_CURRENT_STAGE_OUTCOME).replace(currentOutcome)
Expand All @@ -275,7 +268,7 @@ List<ItemDelta<?,?>> getDeltasToAdvanceCases(AccessCertificationCampaignType cam
.asItemDeltas());
}

LOGGER.debug("Created {} deltas to advance {} cases for campaign {}", rv.size(), caseList.size(), ObjectTypeUtil.toShortString(campaign));
LOGGER.debug("Created {} deltas to advance {} cases for campaign {}", rv.size(), caseList.size(), toShortString(campaign));
return rv;
}

Expand All @@ -284,7 +277,7 @@ List<ItemDelta<?,?>> createOutcomeDeltas(AccessCertificationCampaignType campaig
List<ItemDelta<?,?>> rv = new ArrayList<>();

if (LOGGER.isTraceEnabled()) {
LOGGER.trace("Updating current outcome for cases in {}", ObjectTypeUtil.toShortString(campaign));
LOGGER.trace("Updating current outcome for cases in {}", toShortString(campaign));
}
List<AccessCertificationCaseType> caseList = queryHelper.searchCases(campaign.getOid(), null, null, result);

Expand Down
Expand Up @@ -86,7 +86,7 @@ private ObjectQuery replaceFilter(ObjectQuery query, ObjectFilter newFilter) {
}

// public because of testing
public List<AccessCertificationWorkItemType> searchWorkItems(ObjectQuery query, String reviewerOid, boolean notDecidedOnly,
public List<AccessCertificationWorkItemType> searchWorkItems(ObjectQuery baseWorkItemsQuery, String reviewerOid, boolean notDecidedOnly,
Collection<SelectorOptions<GetOperationOptions>> options, Task task, OperationResult result)
throws SchemaException, ObjectNotFoundException {

Expand All @@ -106,7 +106,7 @@ public List<AccessCertificationWorkItemType> searchWorkItems(ObjectQuery query,
} else {
filterToAdd = reviewerAndEnabledFilter;
}
newQuery = replaceFilter(query, filterToAdd);
newQuery = replaceFilter(baseWorkItemsQuery, filterToAdd);

// retrieve cases, filtered
List<AccessCertificationWorkItemType> workItems = repositoryService.searchContainers(AccessCertificationWorkItemType.class, newQuery, options, result);
Expand Down
Expand Up @@ -39,6 +39,8 @@
import com.evolveum.midpoint.xml.ns._public.common.common_3.*;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.Validate;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;
Expand Down Expand Up @@ -86,7 +88,7 @@ public class CertificationManagerImpl implements CertificationManager {
public static final String OPERATION_OPEN_NEXT_STAGE = INTERFACE_DOT + "openNextStage";
public static final String OPERATION_CLOSE_CURRENT_STAGE = INTERFACE_DOT + "closeCurrentStage";
public static final String OPERATION_RECORD_DECISION = INTERFACE_DOT + "recordDecision";
public static final String OPERATION_SEARCH_DECISIONS = INTERFACE_DOT + "searchDecisionsToReview";
public static final String OPERATION_SEARCH_DECISIONS = INTERFACE_DOT + "searchOpenWorkItems";
public static final String OPERATION_SEARCH_OPEN_WORK_ITEMS = INTERFACE_DOT + "searchOpenWorkItems";
public static final String OPERATION_CLOSE_CAMPAIGN = INTERFACE_DOT + "closeCampaign";
public static final String OPERATION_GET_CAMPAIGN_STATISTICS = INTERFACE_DOT + "getCampaignStatistics";
Expand Down Expand Up @@ -324,7 +326,7 @@ public List<AccessCertificationCaseType> searchDecisionsToReview(ObjectQuery cas
}

@Override
public List<AccessCertificationWorkItemType> searchOpenWorkItems(ObjectQuery caseQuery, boolean notDecidedOnly,
public List<AccessCertificationWorkItemType> searchOpenWorkItems(ObjectQuery baseWorkItemsQuery, boolean notDecidedOnly,
Collection<SelectorOptions<GetOperationOptions>> options, Task task, OperationResult parentResult)
throws ObjectNotFoundException, SchemaException, SecurityViolationException {

Expand All @@ -335,7 +337,7 @@ public List<AccessCertificationWorkItemType> searchOpenWorkItems(ObjectQuery cas
null, null, null, null, result);

String reviewerOid = securityEnforcer.getPrincipal().getOid();
return queryHelper.searchWorkItems(caseQuery, reviewerOid, notDecidedOnly, options, task, result);
return queryHelper.searchWorkItems(baseWorkItemsQuery, reviewerOid, notDecidedOnly, options, task, result);
} catch (RuntimeException e) {
result.recordFatalError("Couldn't search for certification work items: unexpected exception: " + e.getMessage(), e);
throw e;
Expand All @@ -345,19 +347,15 @@ public List<AccessCertificationWorkItemType> searchOpenWorkItems(ObjectQuery cas
}

@Override
public void recordDecision(String campaignOid, long caseId, long workItemId, AccessCertificationResponseType response,
String comment, Task task, OperationResult parentResult) throws ObjectNotFoundException, SchemaException,
public void recordDecision(@NotNull String campaignOid, long caseId, long workItemId, @Nullable AccessCertificationResponseType response,
@Nullable String comment, Task task, OperationResult parentResult) throws ObjectNotFoundException, SchemaException,
SecurityViolationException, ObjectAlreadyExistsException {

Validate.notNull(campaignOid, "campaignOid");
Validate.notNull(response, "decision");

OperationResult result = parentResult.createSubresult(OPERATION_RECORD_DECISION);
try {
securityEnforcer.authorize(ModelAuthorizationAction.RECORD_CERTIFICATION_DECISION.getUrl(), null,
null, null, null, null, result);
AccessCertificationCampaignType campaign = generalHelper.getCampaign(campaignOid, null, task, result);
caseHelper.recordDecision(campaign, caseId, workItemId, response, comment, task, result);
caseHelper.recordDecision(campaignOid, caseId, workItemId, response, comment, task, result);
} catch (RuntimeException e) {
result.recordFatalError("Couldn't record reviewer decision: unexpected exception: " + e.getMessage(), e);
throw e;
Expand Down

0 comments on commit 0def79e

Please sign in to comment.