Skip to content

Commit

Permalink
Backport for role mining functionality
Browse files Browse the repository at this point in the history
1. Add role analysis service (RoleAnalysisService) for basic role-mining operations
2. Remove duplicate code
3. Add progress status information in clusters and session tables
4. Change detection pattern logic
5. Fix minor issues.

NOTE: no schema changes
  • Loading branch information
tchrapovic committed Nov 16, 2023
1 parent 3f4336d commit 9792c8f
Show file tree
Hide file tree
Showing 86 changed files with 4,302 additions and 2,997 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
import javax.xml.namespace.QName;

import com.evolveum.midpoint.model.api.authentication.GuiProfiledPrincipal;
import com.evolveum.midpoint.model.api.mining.RoleAnalysisService;
import com.evolveum.midpoint.model.api.simulation.SimulationResultManager;

import com.evolveum.midpoint.repo.common.ObjectOperationPolicyHelper;
Expand Down Expand Up @@ -552,6 +553,10 @@ public SimulationResultManager getSimulationResultManager() {
return simulationResultManager;
}

public RoleAnalysisService getRoleAnalysisService() {
return getMidpointApplication().getRoleAnalysisService();
}

public CertGuiHandlerRegistry getCertGuiHandlerRegistry() {
return certGuiHandlerRegistry;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
import com.evolveum.midpoint.gui.api.factory.wrapper.PrismObjectWrapperFactory;
import com.evolveum.midpoint.gui.api.factory.wrapper.WrapperContext;
import com.evolveum.midpoint.gui.api.prism.wrapper.PrismValueWrapper;
import com.evolveum.midpoint.model.api.mining.RoleAnalysisService;
import com.evolveum.midpoint.schema.merger.AdminGuiConfigurationMergeManager;
import com.evolveum.midpoint.model.api.ModelInteractionService;
import com.evolveum.midpoint.model.api.ModelService;
Expand Down Expand Up @@ -109,4 +110,6 @@ default ObjectResolver getModelObjectResolver() {
* Experimental, functionality will be probably later hidden behind {@link ModelInteractionService}
*/
SimulationResultManager getSimulationResultManager();

RoleAnalysisService getRoleAnalysisService();
}
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
import org.apache.wicket.markup.repeater.Item;
import org.apache.wicket.markup.repeater.RepeatingView;
import org.apache.wicket.model.IModel;
import org.apache.wicket.model.LoadableDetachableModel;
import org.apache.wicket.model.Model;
import org.apache.wicket.model.util.ListModel;
import org.apache.wicket.request.mapper.parameter.PageParameters;
Expand Down Expand Up @@ -113,7 +114,7 @@ private BoxedTablePanel<BusinessRoleDto> getTable() {
private BoxedTablePanel<BusinessRoleDto> generateTable(RoleMiningProvider<BusinessRoleDto> provider) {

BoxedTablePanel<BusinessRoleDto> table = new BoxedTablePanel<>(
ID_MODIFICATION_TARGET_PANEL, provider, initColumns(provider)) {
ID_MODIFICATION_TARGET_PANEL, provider, initColumns()) {
@Override
protected WebMarkupContainer createButtonToolbar(String id) {
//TODO add possibility to assign other candidate.
Expand Down Expand Up @@ -167,7 +168,7 @@ public Component getFooterButtonToolbar() {
return table;
}

private List<IColumn<BusinessRoleDto, String>> initColumns(RoleMiningProvider<BusinessRoleDto> provider) {
private List<IColumn<BusinessRoleDto, String>> initColumns() {

List<IColumn<BusinessRoleDto, String>> columns = new ArrayList<>();

Expand Down Expand Up @@ -222,7 +223,7 @@ public void onClick(AjaxRequestTarget target) {

});

columns.add(new AbstractColumn<>(createStringResource("Status")) {
columns.add(new AbstractColumn<>(createStringResource("RoleAnalysis.modificationTargetPanel.status")) {

@Override
public String getSortProperty() {
Expand All @@ -248,7 +249,8 @@ public void populateItem(Item<ICellPopulator<BusinessRoleDto>> item, String comp

});

columns.add(new AbstractColumn<>(createStringResource("Added Assignment")) {
columns.add(new AbstractColumn<>(createStringResource(
"RoleAnalysis.modificationTargetPanel.added.access")) {

@Override
public String getSortProperty() {
Expand All @@ -269,7 +271,8 @@ public void populateItem(Item<ICellPopulator<BusinessRoleDto>> item, String comp

});

columns.add(new AbstractColumn<>(createStringResource("Replaced Assignment")) {
columns.add(new AbstractColumn<>(createStringResource(
"RoleAnalysis.modificationTargetPanel.replaced.assignments")) {

@Override
public String getSortProperty() {
Expand All @@ -290,7 +293,8 @@ public void populateItem(Item<ICellPopulator<BusinessRoleDto>> item, String comp

});

columns.add(new AbstractColumn<>(createStringResource("Current Assignment count")) {
columns.add(new AbstractColumn<>(createStringResource(
"RoleAnalysis.modificationTargetPanel.count.assignments")) {

@Override
public String getSortProperty() {
Expand All @@ -311,7 +315,8 @@ public void populateItem(Item<ICellPopulator<BusinessRoleDto>> item, String comp

});

columns.add(new AbstractColumn<>(createStringResource("Final Assignment count")) {
columns.add(new AbstractColumn<>(createStringResource(
"RoleAnalysis.modificationTargetPanel.count.assignments.final")) {

@Override
public String getSortProperty() {
Expand Down Expand Up @@ -358,14 +363,19 @@ protected String load() {
};

AjaxIconButton ajaxIncludeButton = new AjaxIconButton(repeatingView.newChildId(), loadableIncludeModel,
createStringResource("Include")) {
new LoadableDetachableModel<>() {
@Override
protected String load() {
if (model.getObject().isInclude()) {
return createStringResource("RoleAnalysis.exclude").getString();
}
return createStringResource("RoleAnalysis.include").getString();
}
}) {
@Override
public void onClick(AjaxRequestTarget ajaxRequestTarget) {
model.getObject().setInclude(!model.getObject().isInclude());
BusinessRoleApplicationDto patternDeltas = getObjectDetailsModels().getPatternDeltas();
patternDeltas.setBusinessRoleDtos(provider.getAvailableData());
ajaxRequestTarget.add(this);
getTable().replaceWith(generateTable(provider));
ajaxRequestTarget.add(getTable().setOutputMarkupId(true));
}
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -202,6 +202,12 @@ protected void savePerformed(AjaxRequestTarget target) {
PageAssignmentHolderDetails.this.savePerformed(target);
}

@Override
protected void backPerformed(AjaxRequestTarget target) {
super.backPerformed(target);
onBackPerform(target);
}

@Override
protected void addButtons(RepeatingView repeatingView) {
addAdditionalButtons(repeatingView);
Expand All @@ -221,7 +227,9 @@ protected boolean hasUnsavedChanges(AjaxRequestTarget target) {
}

protected void afterDeletePerformed(AjaxRequestTarget target) {
}

protected void onBackPerform(AjaxRequestTarget target) {
}

protected void addAdditionalButtons(RepeatingView repeatingView) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,54 +6,49 @@
*/
package com.evolveum.midpoint.gui.impl.page.admin.role.component.wizard;

import static com.evolveum.midpoint.gui.impl.page.admin.role.mining.utils.RoleAnalysisObjectUtils.clusterMigrationRecompute;
import static com.evolveum.midpoint.gui.impl.page.admin.role.mining.utils.RoleAnalysisObjectUtils.getRoleTypeObject;
import static com.evolveum.midpoint.repo.api.RepositoryService.LOGGER;

import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

import com.evolveum.midpoint.gui.api.page.PageBase;
import com.evolveum.midpoint.gui.impl.page.admin.role.mining.page.page.PageRoleAnalysis;

import com.evolveum.midpoint.gui.impl.util.DetailsPageUtil;
import com.evolveum.midpoint.web.util.OnePageParameterEncoder;
import java.util.UUID;

import org.apache.commons.collections4.CollectionUtils;
import org.apache.wicket.ajax.AjaxRequestTarget;
import org.apache.wicket.request.mapper.parameter.PageParameters;

import com.evolveum.midpoint.gui.api.component.wizard.TileEnum;
import com.evolveum.midpoint.gui.api.component.wizard.WizardModel;
import com.evolveum.midpoint.gui.api.component.wizard.WizardPanel;
import com.evolveum.midpoint.gui.api.component.wizard.WizardStep;
import com.evolveum.midpoint.gui.api.page.PageBase;
import com.evolveum.midpoint.gui.impl.component.wizard.AbstractWizardPanel;
import com.evolveum.midpoint.gui.impl.component.wizard.WizardPanelHelper;
import com.evolveum.midpoint.gui.impl.page.admin.ObjectChangesExecutorImpl;
import com.evolveum.midpoint.gui.impl.page.admin.abstractrole.AbstractRoleDetailsModel;
import com.evolveum.midpoint.gui.impl.page.admin.role.mining.model.BusinessRoleApplicationDto;
import com.evolveum.midpoint.gui.impl.page.admin.role.mining.model.BusinessRoleDto;
import com.evolveum.midpoint.model.api.ActivitySubmissionOptions;
import com.evolveum.midpoint.model.api.ModelService;
import com.evolveum.midpoint.gui.impl.page.admin.role.mining.page.page.PageRoleAnalysis;
import com.evolveum.midpoint.gui.impl.util.DetailsPageUtil;
import com.evolveum.midpoint.model.api.mining.RoleAnalysisService;
import com.evolveum.midpoint.prism.PrismObject;
import com.evolveum.midpoint.prism.delta.ObjectDelta;
import com.evolveum.midpoint.schema.ObjectDeltaOperation;
import com.evolveum.midpoint.schema.result.OperationResult;
import com.evolveum.midpoint.task.api.Task;
import com.evolveum.midpoint.util.exception.CommonException;
import com.evolveum.midpoint.util.exception.SchemaException;
import com.evolveum.midpoint.web.component.util.VisibleEnableBehaviour;
import com.evolveum.midpoint.web.util.OnePageParameterEncoder;
import com.evolveum.midpoint.xml.ns._public.common.common_3.*;

import org.apache.wicket.request.mapper.parameter.PageParameters;

/**
* @author lskublik
*/
public class BusinessRoleWizardPanel extends AbstractWizardPanel<RoleType, AbstractRoleDetailsModel<RoleType>> {

private static final String DOT_CLASS = BusinessRoleWizardPanel.class.getName() + ".";
private static final String OP_PERFORM_MIGRATION = DOT_CLASS + "performMigration";

public BusinessRoleWizardPanel(String id, WizardPanelHelper<RoleType, AbstractRoleDetailsModel<RoleType>> helper) {
super(id, helper);
}
Expand Down Expand Up @@ -140,16 +135,29 @@ private void businessRoleMigrationPerform(AjaxRequestTarget target) {
BusinessRoleApplicationDto patternDeltas = getHelper().getDetailsModel().getPatternDeltas();

if (patternDeltas != null && !patternDeltas.getBusinessRoleDtos().isEmpty()) {
ModelService modelService = getPageBase().getModelService();
Collection<ObjectDeltaOperation<? extends ObjectType>> executedDeltas = new ObjectChangesExecutorImpl()
.executeChanges(deltas, false, task, result, target);

String roleOid = ObjectDeltaOperation.findAddDeltaOidRequired(executedDeltas, RoleType.class);
clusterMigrationRecompute(getPageBase(), patternDeltas.getCluster().getOid(), roleOid, task, result);

PrismObject<RoleType> roleObject = getRoleTypeObject(modelService, roleOid, task, result);
RoleAnalysisService roleAnalysisService = getPageBase().getRoleAnalysisService();
PrismObject<RoleType> roleObject = roleAnalysisService
.getRoleTypeObject(roleOid, task, result);
if (roleObject != null) {
executeMigrationTask(result, task, patternDeltas.getBusinessRoleDtos(), roleObject);
roleAnalysisService.clusterObjectMigrationRecompute(
patternDeltas.getCluster().getOid(), roleOid, task, result);

String taskOid = UUID.randomUUID().toString();

ActivityDefinitionType activity = null;
try {
activity = createActivity(patternDeltas.getBusinessRoleDtos(), roleOid);
} catch (SchemaException e) {
LOGGER.error("Couldn't create activity for role migration: " + roleOid);
}
if (activity != null) {
roleAnalysisService.executeMigrationTask(
patternDeltas.getCluster(), activity, roleObject, taskOid, null, task, result);
}
}

} else {
Expand Down Expand Up @@ -189,24 +197,6 @@ private void onFinishBasicWizardPerformed(AjaxRequestTarget target) {
}
}

private void executeMigrationTask(OperationResult result, Task task, List<BusinessRoleDto> patternDeltas, PrismObject<RoleType> roleObject) {
try {
ActivityDefinitionType activity = createActivity(patternDeltas, roleObject.getOid());

getPageBase().getModelInteractionService().submit(
activity,
ActivitySubmissionOptions.create()
.withTaskTemplate(new TaskType()
.name("Migration role (" + roleObject.getName().toString() + ")"))
.withArchetypes(
SystemObjectsType.ARCHETYPE_UTILITY_TASK.value()),
task, result);

} catch (CommonException e) {
LOGGER.error("Failed to execute role {} migration activity: ", roleObject.getOid(), e);
}
}

private ActivityDefinitionType createActivity(List<BusinessRoleDto> patternDeltas, String roleOid) throws SchemaException {

ObjectReferenceType objectReferenceType = new ObjectReferenceType();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
import com.evolveum.midpoint.xml.ns._public.common.common_3.RoleType;

@PanelType(name = "brw-candidateMembers")
@PanelInstance(identifier = "brw-access",
@PanelInstance(identifier = "brw-candidateMembers",
applicableForType = RoleType.class,
applicableForOperation = OperationTypeType.WIZARD,
display = @PanelDisplay(label = "PageRole.wizard.step.access.applicationRole", icon = "fa fa-list"),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,20 +17,33 @@
import com.evolveum.midpoint.xml.ns._public.common.common_3.RoleAnalysisClusterType;
import com.evolveum.midpoint.xml.ns._public.common.common_3.RoleType;

import org.jetbrains.annotations.NotNull;

/**
* The BusinessRoleApplicationDto class represents a Data Transfer Object (DTO) that holds
* information about a specific role, its associated cluster, and a list of BusinessRoleDtos that holds information
* about a user's delta to a specific role.
*/
public class BusinessRoleApplicationDto implements Serializable {

PrismObject<RoleAnalysisClusterType> cluster;
PrismObject<RoleType> businessRole;
List<BusinessRoleDto> businessRoleDtos;

public BusinessRoleApplicationDto(PrismObject<RoleAnalysisClusterType> cluster, PrismObject<RoleType> businessRole,
List<BusinessRoleDto> businessRoleDtos) {
public BusinessRoleApplicationDto(
@NotNull PrismObject<RoleAnalysisClusterType> cluster,
@NotNull PrismObject<RoleType> businessRole,
@NotNull List<BusinessRoleDto> businessRoleDtos) {
this.cluster = cluster;
this.businessRole = businessRole;
this.businessRoleDtos = businessRoleDtos;
}


/**
* Updates the value of the inducements of the business role.
*
* @param inducements The list of inducements to be updated.
*/
public void updateValue(List<AssignmentType> inducements) {
Set<String> inducementsOidSet = new HashSet<>();
for (AssignmentType inducement : inducements) {
Expand Down

0 comments on commit 9792c8f

Please sign in to comment.