Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@

package com.evolveum.midpoint.gui.impl.page.admin.component.preview;

import java.io.Serial;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
Expand All @@ -17,12 +19,13 @@

import com.evolveum.midpoint.gui.api.component.BasePanel;
import com.evolveum.midpoint.gui.api.model.LoadableModel;
import com.evolveum.midpoint.gui.api.page.PageBase;
import com.evolveum.midpoint.gui.api.util.WebComponentUtil;
import com.evolveum.midpoint.gui.impl.page.admin.focus.PageFocusPreviewChanges;
import com.evolveum.midpoint.model.api.context.ModelContext;
import com.evolveum.midpoint.model.api.visualizer.ModelContextVisualization;
import com.evolveum.midpoint.model.api.visualizer.Visualization;
import com.evolveum.midpoint.repo.common.ObjectResolver;
import com.evolveum.midpoint.schema.TaskExecutionMode;
import com.evolveum.midpoint.schema.result.OperationResult;
import com.evolveum.midpoint.task.api.Task;
import com.evolveum.midpoint.util.DebugUtil;
Expand All @@ -47,7 +50,7 @@
import com.evolveum.midpoint.xml.ns._public.common.common_3.ObjectType;
import com.evolveum.midpoint.xml.ns._public.common.common_3.PolicyRuleEnforcerPreviewOutputType;

public class PreviewChangesTabPanel<O extends ObjectType> extends BasePanel<ModelContext<O>> {
public class PreviewChangesTabPanel extends BasePanel<Void> {
private static final long serialVersionUID = 1L;

private static final String ID_PRIMARY_DELTAS = "primaryDeltas";
Expand All @@ -64,10 +67,13 @@ public class PreviewChangesTabPanel<O extends ObjectType> extends BasePanel<Mode
private IModel<List<EvaluatedTriggerGroupDto>> policyViolationsModel;
private IModel<List<ApprovalProcessExecutionInformationDto>> approvalsModel;

private final PreviewData data;

private static final Trace LOGGER = TraceManager.getTrace(PreviewChangesTabPanel.class);

public PreviewChangesTabPanel(String id, IModel<ModelContext<O>> contextModel) {
super(id, contextModel);
public PreviewChangesTabPanel(String id, PreviewData data) {
super(id);
this.data = data;
}

@Override
Expand All @@ -78,15 +84,28 @@ protected void onInitialize() {
initLayout();
}

/** Initializes Wicket models from already extracted serializable preview data. */
private void initModels() {
primaryModel = Model.ofList(data.primary());
secondaryModel = Model.ofList(data.secondary());
policyViolationsModel = Model.ofList(data.policyViolations());
approvalsModel = Model.ofList(data.approvals());
}

/**
* Extracts the data needed by the preview page from live model contexts.
*
* The returned data is safe to keep in Wicket page state; the original model contexts are not.
*/
public static <O extends ObjectType> PreviewData createPreviewData(
String title, ModelContext<O> modelContext, PageBase pageBase) {
ModelContextVisualization mcVisualization;

ModelContext<O> modelContext = getModelObject();
try {
Task task = getPageBase().createSimpleTask("visualize");
Task task = pageBase.createSimpleTask("visualize");
OperationResult result = task.getResult();

mcVisualization = getPageBase().getModelInteractionService().visualizeModelContext(modelContext, task, result);
mcVisualization = pageBase.getModelInteractionService().visualizeModelContext(modelContext, task, result);
} catch (SchemaException | ExpressionEvaluationException | ConfigurationException e) {
throw new SystemException(e); // TODO
}
Expand All @@ -102,41 +121,46 @@ private void initModels() {
final List<VisualizationDto> primaryList = primary.stream().map(v -> new VisualizationDto(v)).collect(Collectors.toList());
final List<VisualizationDto> secondaryList = secondary.stream().map(v -> new VisualizationDto(v)).collect(Collectors.toList());

primaryModel = () -> primaryList;
secondaryModel = () -> secondaryList;

PolicyRuleEnforcerPreviewOutputType enforcements = modelContext != null
? modelContext.getPolicyRuleEnforcerPreviewOutput()
: null;
List<EvaluatedTriggerGroupDto> triggerGroups = enforcements != null
? Collections.singletonList(EvaluatedTriggerGroupDto.initializeFromRules(enforcements.getRule(), false, null))
: Collections.emptyList();
policyViolationsModel = Model.ofList(triggerGroups);

List<ApprovalSchemaExecutionInformationType> approvalsExecutionList = modelContext != null
? modelContext.getHookPreviewResults(ApprovalSchemaExecutionInformationType.class)
: Collections.emptyList();
List<ApprovalProcessExecutionInformationDto> approvals = new ArrayList<>();
if (!approvalsExecutionList.isEmpty()) {
Task opTask = getPageBase().createSimpleTask(PageFocusPreviewChanges.class + ".createApprovals"); // TODO
Task opTask = pageBase.createSimpleTask(PageFocusPreviewChanges.class + ".createApprovals"); // TODO
OperationResult result = opTask.getResult();
try {
for (ApprovalSchemaExecutionInformationType execution : approvalsExecutionList) {
approvals.add(ApprovalProcessExecutionInformationDto
.createFrom(execution, true, opTask, result,
PreviewChangesTabPanel.this.getPageBase())); // TODO reuse session
pageBase)); // TODO reuse session
}
result.computeStatus();
} catch (Throwable t) {
LoggingUtils.logUnexpectedException(LOGGER, "Couldn't prepare approval information", t);
result.recordFatalError(
createStringResource("PreviewChangesTabPanel.message.prepareApproval.fatalError", t.getMessage()).getString(), t);
pageBase.createStringResource(
"PreviewChangesTabPanel.message.prepareApproval.fatalError", t.getMessage()).getString(), t);
}
if (WebComponentUtil.showResultInPage(result)) {
getPageBase().showResult(result);
pageBase.showResult(result);
}
}
approvalsModel = Model.ofList(approvals);

return new PreviewData(
title,
primaryList,
secondaryList,
triggerGroups,
approvals,
modelContext != null
&& TaskExecutionMode.SIMULATED_PRODUCTION.equals(modelContext.getTaskExecutionMode()));
}

private IModel<VisualizationDto> createVisualizationModel(IModel<List<VisualizationDto>> model, String oneKey, String moreKey) {
Expand Down Expand Up @@ -208,4 +232,25 @@ private boolean approvalsEmpty() {
private boolean violationsEmpty() {
return EvaluatedTriggerGroupDto.isEmpty(policyViolationsModel.getObject());
}

/**
* Serializable page-state representation of one preview tab.
*
* It is created once while rendering the preview page and then reused by tab panels
* and button visibility checks during later Wicket requests.
*/
public record PreviewData(
String title,
List<VisualizationDto> primary,
List<VisualizationDto> secondary,
List<EvaluatedTriggerGroupDto> policyViolations,
List<ApprovalProcessExecutionInformationDto> approvals,
boolean withProductionConfiguration) implements Serializable {

@Serial private static final long serialVersionUID = 1L;

public boolean violationsEmpty() {
return EvaluatedTriggerGroupDto.isEmpty(policyViolations);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,9 @@
package com.evolveum.midpoint.gui.impl.page.admin.focus;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;

import com.evolveum.midpoint.schema.TaskExecutionMode;

import org.apache.wicket.Component;
import org.apache.wicket.RestartResponseException;
import org.apache.wicket.ajax.AjaxRequestTarget;
Expand All @@ -30,6 +27,7 @@
import com.evolveum.midpoint.gui.api.page.PageBase;
import com.evolveum.midpoint.gui.api.util.WebComponentUtil;
import com.evolveum.midpoint.gui.impl.page.admin.component.preview.PreviewChangesTabPanel;
import com.evolveum.midpoint.gui.impl.page.admin.component.preview.PreviewChangesTabPanel.PreviewData;
import com.evolveum.midpoint.model.api.context.ModelContext;
import com.evolveum.midpoint.prism.PrismObject;
import com.evolveum.midpoint.security.api.AuthorizationConstants;
Expand All @@ -40,11 +38,9 @@
import com.evolveum.midpoint.web.component.breadcrumbs.Breadcrumb;
import com.evolveum.midpoint.web.component.form.MidpointForm;
import com.evolveum.midpoint.web.component.util.VisibleBehaviour;
import com.evolveum.midpoint.web.page.admin.workflow.dto.EvaluatedTriggerGroupDto;
import com.evolveum.midpoint.web.util.OnePageParameterEncoder;
import com.evolveum.midpoint.xml.ns._public.common.common_3.AbstractRoleType;
import com.evolveum.midpoint.xml.ns._public.common.common_3.ObjectType;
import com.evolveum.midpoint.xml.ns._public.common.common_3.PolicyRuleEnforcerPreviewOutputType;

@PageDescriptor(
urls = {
Expand All @@ -65,7 +61,13 @@ public class PageFocusPreviewChanges<O extends ObjectType> extends PageBase {

private static final Trace LOGGER = TraceManager.getTrace(PageFocusPreviewChanges.class);

private Map<PrismObject<O>, ModelContext<O>> modelContextMap;
private List<PreviewData> previewData;
/*
* Live model contexts may contain non-serializable model execution state
* (e.g. LensContext -> MagicAssignment/Holder). Keep them only as transient
* input until serializable preview data is created.
*/
private transient Map<PrismObject<O>, ModelContext<O>> modelContextMap;

private PageBase previousPage;

Expand All @@ -78,9 +80,28 @@ public PageFocusPreviewChanges(Map<PrismObject<O>, ModelContext<O>> modelContext
this.previousPage = previousPage;
}

/**
* Extracts the data needed by the preview page from live model contexts.
*
* The returned data is safe to keep in Wicket page state; the original model contexts are not.
*/
private List<PreviewData> createPreviewData(Map<PrismObject<O>, ModelContext<O>> modelContextMap) {
List<PreviewData> previewData = new ArrayList<>();
modelContextMap.forEach((object, modelContext) ->
previewData.add(
PreviewChangesTabPanel.createPreviewData(
getTabPanelTitleModel(object).getObject(), modelContext, this)));
return previewData;
}

@Override
protected void onInitialize() {
super.onInitialize();
// Wicket page state must contain only the serializable preview representation.
if (previewData == null) {
previewData = createPreviewData(modelContextMap);
modelContextMap = null;
}
initLayout();
}

Expand Down Expand Up @@ -129,24 +150,17 @@ public void onClick(AjaxRequestTarget target) {
}

private boolean isWithProductionConfiguration() {
for (ModelContext<O> modelContext : modelContextMap.values()) {
if (modelContext != null && TaskExecutionMode.SIMULATED_PRODUCTION.equals(modelContext.getTaskExecutionMode())) {
for (PreviewData previewChange : previewData) {
if (previewChange.withProductionConfiguration()) {
return true;
}
}
return false;
}

//TODO relocate the logic from the loop to some util method, code repeats in PreviewChangesTabPanel
private boolean violationsEmpty() {
for (ModelContext<O> modelContext : modelContextMap.values()) {
PolicyRuleEnforcerPreviewOutputType enforcements = modelContext != null
? modelContext.getPolicyRuleEnforcerPreviewOutput()
: null;
List<EvaluatedTriggerGroupDto> triggerGroups = enforcements != null
? Collections.singletonList(EvaluatedTriggerGroupDto.initializeFromRules(enforcements.getRule(), false, null))
: Collections.emptyList();
if (!EvaluatedTriggerGroupDto.isEmpty(triggerGroups)) {
for (PreviewData previewChange : previewData) {
if (!previewChange.violationsEmpty()) {
return false;
}
}
Expand All @@ -155,15 +169,15 @@ private boolean violationsEmpty() {

private List<ITab> createTabs() {
List<ITab> tabs = new ArrayList<>();
modelContextMap.forEach((object, modelContext) -> {
previewData.forEach(previewChange -> {

tabs.add(new PanelTab(getTabPanelTitleModel(object)) {
tabs.add(new PanelTab(Model.of(previewChange.title())) {

private static final long serialVersionUID = 1L;

@Override
public WebMarkupContainer createPanel(String panelId) {
return new PreviewChangesTabPanel(panelId, Model.of(modelContext));
return new PreviewChangesTabPanel(panelId, previewChange);
}
});
});
Expand Down
Loading
Loading