/*
* Copyright (c) 2010-2016 Evolveum
*
* 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 com.evolveum.midpoint.web.page.admin.certification;
import com.evolveum.midpoint.certification.api.AccessCertificationApiConstants;
import com.evolveum.midpoint.gui.api.model.LoadableModel;
import com.evolveum.midpoint.gui.api.model.NonEmptyLoadableModel;
import com.evolveum.midpoint.gui.api.util.WebComponentUtil;
import com.evolveum.midpoint.gui.api.util.WebModelServiceUtils;
import com.evolveum.midpoint.model.api.AccessCertificationService;
import com.evolveum.midpoint.prism.PrismObject;
import com.evolveum.midpoint.prism.query.ObjectQuery;
import com.evolveum.midpoint.schema.result.OperationResult;
import com.evolveum.midpoint.task.api.Task;
import com.evolveum.midpoint.util.logging.LoggingUtils;
import com.evolveum.midpoint.util.logging.Trace;
import com.evolveum.midpoint.util.logging.TraceManager;
import com.evolveum.midpoint.web.application.AuthorizationAction;
import com.evolveum.midpoint.web.application.PageDescriptor;
import com.evolveum.midpoint.web.component.AjaxButton;
import com.evolveum.midpoint.web.component.AjaxSubmitButton;
import com.evolveum.midpoint.web.component.data.BoxedTablePanel;
import com.evolveum.midpoint.web.component.data.Table;
import com.evolveum.midpoint.web.component.data.column.DoubleButtonColumn.BUTTON_COLOR_CLASS;
import com.evolveum.midpoint.web.component.data.column.MultiButtonColumn;
import com.evolveum.midpoint.web.component.util.VisibleBehaviour;
import com.evolveum.midpoint.web.component.util.VisibleEnableBehaviour;
import com.evolveum.midpoint.web.page.admin.certification.dto.CertCampaignDto;
import com.evolveum.midpoint.web.page.admin.certification.dto.CertCaseDto;
import com.evolveum.midpoint.web.page.admin.certification.dto.CertCaseDtoProvider;
import com.evolveum.midpoint.web.page.admin.certification.helpers.AvailableResponses;
import com.evolveum.midpoint.web.session.UserProfileStorage;
import com.evolveum.midpoint.web.util.OnePageParameterEncoder;
import com.evolveum.midpoint.xml.ns._public.common.common_3.*;
import org.apache.wicket.Component;
import org.apache.wicket.ajax.AjaxRequestTarget;
import org.apache.wicket.extensions.markup.html.repeater.data.sort.SortOrder;
import org.apache.wicket.extensions.markup.html.repeater.data.table.IColumn;
import org.apache.wicket.extensions.markup.html.repeater.data.table.PropertyColumn;
import org.apache.wicket.markup.html.WebMarkupContainer;
import org.apache.wicket.markup.html.basic.Label;
import org.apache.wicket.markup.html.form.Form;
import org.apache.wicket.model.AbstractReadOnlyModel;
import org.apache.wicket.model.IModel;
import org.apache.wicket.model.Model;
import org.apache.wicket.model.PropertyModel;
import org.apache.wicket.request.mapper.parameter.PageParameters;
import org.apache.wicket.util.string.StringValue;
import org.jetbrains.annotations.NotNull;
import javax.xml.namespace.QName;
import java.util.ArrayList;
import java.util.List;
import static com.evolveum.midpoint.web.page.admin.certification.CertDecisionHelper.WhichObject.OBJECT;
import static com.evolveum.midpoint.web.page.admin.certification.CertDecisionHelper.WhichObject.TARGET;
import static com.evolveum.midpoint.web.page.admin.certification.PageCertCampaigns.*;
import static com.evolveum.midpoint.xml.ns._public.common.common_3.AccessCertificationCasesStatisticsType.*;
/**
* @author mederly
*/
@PageDescriptor(url = "/admin/certification/campaign",
action = {
@AuthorizationAction(actionUri = PageAdminCertification.AUTH_CERTIFICATION_ALL,
label = PageAdminCertification.AUTH_CERTIFICATION_ALL_LABEL,
description = PageAdminCertification.AUTH_CERTIFICATION_ALL_DESCRIPTION),
@AuthorizationAction(actionUri = PageAdminCertification.AUTH_CERTIFICATION_CAMPAIGN,
label = PageAdminCertification.AUTH_CERTIFICATION_CAMPAIGN_LABEL,
description = PageAdminCertification.AUTH_CERTIFICATION_CAMPAIGN_DESCRIPTION)
})
public class PageCertCampaign extends PageAdminCertification {
private static final Trace LOGGER = TraceManager.getTrace(PageCertCampaign.class);
private static final String DOT_CLASS = PageCertCampaign.class.getName() + ".";
private static final String ID_MAIN_FORM = "mainForm";
private static final String ID_STAT_ACCEPT = "statAccept";
private static final String ID_STAT_REVOKE = "statRevoke";
private static final String ID_STAT_REVOKE_REMEDIED = "statRevokeRemedied";
private static final String ID_STAT_REDUCE = "statReduce";
private static final String ID_STAT_REDUCE_REMEDIED = "statReduceRemedied";
private static final String ID_STAT_DELEGATE = "statDelegate";
private static final String ID_STAT_NO_DECISION = "statNoDecision";
private static final String ID_STAT_NO_RESPONSE = "statNoResponse";
private static final String ID_CAMPAIGN_NAME = "campaignName";
private static final String ID_CAMPAIGN_DESCRIPTION = "campaignDescription";
private static final String ID_CAMPAIGN_OWNER = "campaignOwner";
private static final String ID_CAMPAIGN_NUMBER_OF_STAGES = "campaignNumberOfStages";
private static final String ID_CAMPAIGN_CURRENT_STATE = "campaignCurrentState";
private static final String ID_CAMPAIGN_TIME = "campaignTime";
private static final String ID_STAGE_TIME = "stageTime";
private static final String ID_ESCALATION_LEVEL_INFO_CONTAINER = "escalationLevelInfoContainer";
private static final String ID_ESCALATION_LEVEL_INFO = "escalationLevelInfo";
private static final String ID_BACK_BUTTON = "backButton";
private static final String ID_START_CAMPAIGN_BUTTON = "startCampaignButton";
private static final String ID_CLOSE_STAGE_BUTTON = "closeStageButton";
private static final String ID_OPEN_NEXT_STAGE_BUTTON = "openNextStageButton";
private static final String ID_START_REMEDIATION_BUTTON = "startRemediationButton";
private static final String ID_CLOSE_CAMPAIGN_BUTTON = "closeCampaignButton";
private static final String OPERATION_ADVANCE_LIFECYCLE = DOT_CLASS + "advanceLifecycle";
private static final String OPERATION_OPEN_NEXT_STAGE = DOT_CLASS + "openNextStage";
private static final String OPERATION_CLOSE_STAGE = DOT_CLASS + "closeStage";
private static final String OPERATION_CLOSE_CAMPAIGN = DOT_CLASS + "closeCampaign";
private static final String OPERATION_START_REMEDIATION = DOT_CLASS + "startRemediation";
private static final String ID_OUTCOMES_TABLE = "outcomesTable";
private LoadableModel<AccessCertificationCasesStatisticsType> statModel;
private NonEmptyLoadableModel<CertCampaignDto> campaignModel;
private String campaignOid;
CertDecisionHelper helper = new CertDecisionHelper();
public PageCertCampaign(PageParameters parameters) {
StringValue campaignOidValue = parameters.get(OnePageParameterEncoder.PARAMETER);
if (campaignOidValue != null) {
campaignOid = campaignOidValue.toString();
}
initModels();
initLayout();
}
private void initModels() {
statModel = new LoadableModel<AccessCertificationCasesStatisticsType>(false) {
@Override
protected AccessCertificationCasesStatisticsType load() {
return loadStatistics();
}
};
campaignModel = new NonEmptyLoadableModel<CertCampaignDto>(false) {
@NotNull
@Override
protected CertCampaignDto load() {
return loadCampaign();
}
};
}
private AccessCertificationCasesStatisticsType loadStatistics() {
OperationResult result = new OperationResult("dummy"); // todo
AccessCertificationCasesStatisticsType stat = null;
try {
Task task = createSimpleTask("dummy"); // todo
stat = getCertificationService().getCampaignStatistics(campaignOid, false, task, result);
result.recordSuccessIfUnknown();
} catch (Exception ex) {
LoggingUtils.logUnexpectedException(LOGGER, "Couldn't get campaign statistics", ex);
result.recordFatalError("Couldn't get campaign statistics.", ex);
}
result.recomputeStatus();
if (!WebComponentUtil.isSuccessOrHandledError(result)) {
showResult(result);
}
return stat;
}
@NotNull
private CertCampaignDto loadCampaign() {
Task task = createSimpleTask("dummy"); // todo
OperationResult result = task.getResult();
AccessCertificationCampaignType campaign = null;
try {
PrismObject<AccessCertificationCampaignType> campaignObject =
WebModelServiceUtils.loadObject(AccessCertificationCampaignType.class, campaignOid, PageCertCampaign.this, task, result);
if (campaignObject != null) {
campaign = campaignObject.asObjectable();
}
result.recordSuccessIfUnknown();
} catch (Exception ex) {
LoggingUtils.logUnexpectedException(LOGGER, "Couldn't get campaign", ex);
result.recordFatalError("Couldn't get campaign.", ex);
}
result.recomputeStatus();
if (!WebComponentUtil.isSuccessOrHandledError(result)) {
showResult(result);
}
if (campaign != null) {
return new CertCampaignDto(campaign, this, task, result);
} else {
throw redirectBackViaRestartResponseException();
}
}
private void initLayout() {
Form mainForm = new Form(ID_MAIN_FORM);
add(mainForm);
initBasicInfoLayout(mainForm);
initStatisticsLayout(mainForm);
initTableLayout(mainForm);
initButtons(mainForm);
}
private void initBasicInfoLayout(Form mainForm) {
mainForm.add(new Label(ID_CAMPAIGN_NAME, new PropertyModel<>(campaignModel, CertCampaignDto.F_NAME)));
mainForm.add(new Label(ID_CAMPAIGN_DESCRIPTION, new PropertyModel<>(campaignModel, CertCampaignDto.F_DESCRIPTION)));
mainForm.add(new Label(ID_CAMPAIGN_OWNER, new PropertyModel<>(campaignModel, CertCampaignDto.F_OWNER_NAME)));
mainForm.add(new Label(ID_CAMPAIGN_NUMBER_OF_STAGES, new PropertyModel<>(campaignModel, CertCampaignDto.F_NUMBER_OF_STAGES)));
mainForm.add(new Label(ID_CAMPAIGN_CURRENT_STATE, new PropertyModel<>(campaignModel, CertCampaignDto.F_CURRENT_STATE)));
mainForm.add(new Label(ID_CAMPAIGN_TIME, new AbstractReadOnlyModel<String>() {
@Override
public String getObject() {
CertCampaignDto dto = campaignModel.getObject();
return formatDuration(dto.getCampaignStart(), dto.getCampaignEnd());
}
}));
mainForm.add(new Label(ID_STAGE_TIME, new AbstractReadOnlyModel<String>() {
@Override
public String getObject() {
CertCampaignDto dto = campaignModel.getObject();
return formatStageDuration(dto.getStageStart(), dto.getStageDeadline(), dto.getStageEnd());
}
}));
WebMarkupContainer escalationLevelInfoContainer = new WebMarkupContainer(ID_ESCALATION_LEVEL_INFO_CONTAINER);
mainForm.add(escalationLevelInfoContainer);
escalationLevelInfoContainer.add(new Label(ID_ESCALATION_LEVEL_INFO, new PropertyModel<String>(campaignModel, CertCampaignDto.F_ESCALATION_LEVEL_INFO)));
escalationLevelInfoContainer.add(new VisibleBehaviour(() -> campaignModel.getObject().getEscalationLevelInfo() != null));
}
// TODO implement seriously
private String formatStageDuration(String start, String deadline, String end) {
final String showAsEnd = end != null ? end : deadline;
return formatDuration(start, showAsEnd);
}
// TODO implement seriously
private String formatDuration(String start, String end) {
if (start != null && end != null) {
return start + " - " + end;
} else if (start == null && end != null) {
return "? - " + end; // should not occur
} else if (start != null && end == null) {
return start + " -";
} else {
return null;
}
}
private void initTableLayout(Form mainForm) {
CertCaseDtoProvider provider = new CertCaseDtoProvider(PageCertCampaign.this);
provider.setQuery(createCaseQuery());
provider.setCampaignOid(campaignOid);
provider.setSort(AccessCertificationCaseType.F_OBJECT_REF.getLocalPart(), SortOrder.ASCENDING); // default sorting
int itemsPerPage = (int) getItemsPerPage(UserProfileStorage.TableId.PAGE_CERT_CAMPAIGN_OUTCOMES_PANEL);
BoxedTablePanel table = new BoxedTablePanel<>(ID_OUTCOMES_TABLE, provider, initColumns(),
UserProfileStorage.TableId.PAGE_CERT_CAMPAIGN_OUTCOMES_PANEL, itemsPerPage);
table.setShowPaging(true);
table.setOutputMarkupId(true);
table.setItemsPerPage(itemsPerPage);
mainForm.add(table);
}
private List<IColumn<CertCaseDto, String>> initColumns() {
List<IColumn<CertCaseDto, String>> columns = new ArrayList<>();
IColumn column;
column = helper.createTypeColumn(OBJECT, this);
columns.add(column);
column = helper.createObjectNameColumn(this, "PageCertCampaign.table.objectName");
columns.add(column);
column = helper.createTypeColumn(TARGET, this);
columns.add(column);
column = helper.createTargetNameColumn(this, "PageCertCampaign.table.targetName");
columns.add(column);
column = helper.createDetailedInfoColumn(this);
columns.add(column);
if (AccessCertificationApiConstants.EXCLUSION_HANDLER_URI.equals(campaignModel.getObject().getHandlerUri())) {
column = helper.createConflictingNameColumn(this, "PageCertCampaign.table.conflictingTargetName");
columns.add(column);
}
column = new PropertyColumn(createStringResource("PageCertCampaign.table.reviewers"), CertCaseDto.F_CURRENT_REVIEWERS);
columns.add(column);
column = new PropertyColumn(createStringResource("PageCertCampaign.table.reviewedAt"), CertCaseDto.F_REVIEWED_AT);
columns.add(column);
column = new PropertyColumn(createStringResource("PageCertCampaign.table.reviewedBy"), CertCaseDto.F_REVIEWED_BY);
columns.add(column);
column = new PropertyColumn(createStringResource("PageCertCampaign.table.reviewedInStage"), CertCaseDto.F_CURRENT_RESPONSE_STAGE_NUMBER);
columns.add(column);
final AvailableResponses availableResponses = new AvailableResponses(getPage());
final int responses = availableResponses.getCount();
column = new MultiButtonColumn<CertCaseDto>(new Model(), responses+1) {
@Override
public String getCaption(int id) {
return availableResponses.getCaption(id);
}
@Override
public boolean isButtonEnabled(int id, IModel<CertCaseDto> model) {
return false;
}
@Override
public boolean isButtonVisible(int id, IModel<CertCaseDto> model) {
if (id < responses) {
return true;
} else {
return !availableResponses.isAvailable(model.getObject().getOverallOutcome());
}
}
@Override
public String getButtonColorCssClass(int id) {
if (id < responses) {
return getDecisionButtonColor(getRowModel(), availableResponses.getResponseValues().get(id));
} else {
return BUTTON_COLOR_CLASS.DANGER.toString();
}
}
};
columns.add(column);
column = new PropertyColumn(createStringResource("PageCertCampaign.table.comments"), CertCaseDto.F_COMMENTS);
columns.add(column);
column = new PropertyColumn(createStringResource("PageCertCampaign.table.remediedAt"), CertCaseDto.F_REMEDIED_AT);
columns.add(column);
return columns;
}
private String getDecisionButtonColor(IModel<CertCaseDto> model, AccessCertificationResponseType response) {
if (decisionEquals(model, response)) {
return BUTTON_COLOR_CLASS.PRIMARY.toString();
} else {
return BUTTON_COLOR_CLASS.DEFAULT.toString();
}
}
private boolean decisionEquals(IModel<CertCaseDto> model, AccessCertificationResponseType response) {
return model.getObject().getOverallOutcome() == response;
}
private void initStatisticsLayout(Form mainForm) {
mainForm.add(createStatLabel(ID_STAT_ACCEPT, F_MARKED_AS_ACCEPT));
mainForm.add(createStatLabel(ID_STAT_REVOKE, F_MARKED_AS_REVOKE));
mainForm.add(createStatLabel(ID_STAT_REVOKE_REMEDIED, F_MARKED_AS_REVOKE_AND_REMEDIED));
mainForm.add(createStatLabel(ID_STAT_REDUCE, F_MARKED_AS_REDUCE));
mainForm.add(createStatLabel(ID_STAT_REDUCE_REMEDIED, F_MARKED_AS_REDUCE_AND_REMEDIED));
mainForm.add(createStatLabel(ID_STAT_NO_DECISION, F_MARKED_AS_NOT_DECIDE));
mainForm.add(createStatLabel(ID_STAT_NO_RESPONSE, F_WITHOUT_RESPONSE));
}
private Label createStatLabel(String id, QName property) {
return new Label(id, new PropertyModel<Integer>(statModel, property.getLocalPart()));
}
private void initButtons(final Form mainForm) {
AjaxButton backButton = new AjaxButton(ID_BACK_BUTTON, createStringResource("PageCertCampaign.button.back")) {
@Override
public void onClick(AjaxRequestTarget target) {
redirectBack();
}
};
mainForm.add(backButton);
AjaxSubmitButton startCampaignButton = new AjaxSubmitButton(ID_START_CAMPAIGN_BUTTON,
createStringResource("PageCertCampaign.button.startCampaign")) {
@Override
protected void onSubmit(AjaxRequestTarget target, Form<?> form) {
executeCampaignStateOperation(target, OP_OPEN_NEXT_STAGE);
}
};
startCampaignButton.add(new VisibleEnableBehaviour() {
@Override
public boolean isVisible() {
return campaignModel.getObject().getState() == AccessCertificationCampaignStateType.CREATED;
}
});
mainForm.add(startCampaignButton);
AjaxButton nextStageButton = new AjaxButton(ID_OPEN_NEXT_STAGE_BUTTON, createStringResource("PageCertCampaign.button.openNextStage")) {
@Override
public void onClick(AjaxRequestTarget target) {
executeCampaignStateOperation(target, OP_OPEN_NEXT_STAGE);
}
};
nextStageButton.add(new VisibleEnableBehaviour() {
@Override
public boolean isVisible() {
return campaignModel.getObject().getState() == AccessCertificationCampaignStateType.REVIEW_STAGE_DONE
&& campaignModel.getObject().getCurrentStageNumber() < campaignModel.getObject().getNumberOfStages();
}
});
mainForm.add(nextStageButton);
AjaxButton closeStageButton = new AjaxButton(ID_CLOSE_STAGE_BUTTON,
createStringResource("PageCertCampaign.button.closeStage")) {
@Override
public void onClick(AjaxRequestTarget target) {
executeCampaignStateOperation(target, OP_CLOSE_STAGE);
}
};
closeStageButton.add(new VisibleEnableBehaviour() {
@Override
public boolean isVisible() {
return campaignModel.getObject().getState() == AccessCertificationCampaignStateType.IN_REVIEW_STAGE;
}
});
mainForm.add(closeStageButton);
AjaxButton startRemediationButton = new AjaxButton(ID_START_REMEDIATION_BUTTON,
createStringResource("PageCertCampaign.button.startRemediation")) {
@Override
public void onClick(AjaxRequestTarget target) {
executeCampaignStateOperation(target, OP_START_REMEDIATION);
}
};
startRemediationButton.add(new VisibleEnableBehaviour() {
@Override
public boolean isVisible() {
return campaignModel.getObject().getState() == AccessCertificationCampaignStateType.REVIEW_STAGE_DONE
&& campaignModel.getObject().getCurrentStageNumber() == campaignModel.getObject().getNumberOfStages();
}
});
mainForm.add(startRemediationButton);
// TODO reenable when confirmation window is implemented
// AjaxButton closeCampaignButton = new AjaxButton(ID_CLOSE_CAMPAIGN_BUTTON,
// createStringResource("PageCertCampaign.button.closeCampaign")) {
//
// @Override
// public void onClick(AjaxRequestTarget target) {
// executeCampaignStateOperation(target, OP_CLOSE_CAMPAIGN);
// }
// };
// closeCampaignButton.add(new VisibleEnableBehaviour() {
// @Override
// public boolean isVisible() {
// return campaignModel.getObject().getState() != AccessCertificationCampaignStateType.CLOSED;
// }
// });
// mainForm.add(closeCampaignButton);
}
private void executeCampaignStateOperation(AjaxRequestTarget target, String action) {
OperationResult result = new OperationResult(OPERATION_ADVANCE_LIFECYCLE);
try {
AccessCertificationService acs = getCertificationService();
int currentStage = campaignModel.getObject().getCurrentStageNumber();
Task task;
switch (action) {
case OP_START_CAMPAIGN:
case OP_OPEN_NEXT_STAGE:
task = createSimpleTask(OPERATION_OPEN_NEXT_STAGE);
acs.openNextStage(campaignOid, currentStage + 1, task, result);
break;
case OP_CLOSE_STAGE:
task = createSimpleTask(OPERATION_CLOSE_STAGE);
acs.closeCurrentStage(campaignOid, currentStage, task, result);
break;
case OP_START_REMEDIATION:
task = createSimpleTask(OPERATION_START_REMEDIATION);
acs.startRemediation(campaignOid, task, result);
break;
case OP_CLOSE_CAMPAIGN:
task = createSimpleTask(OPERATION_CLOSE_CAMPAIGN);
acs.closeCampaign(campaignOid, task, result);
break;
default:
throw new IllegalStateException("Unknown action: " + action);
}
} catch (Exception ex) {
result.recordFatalError(ex);
} finally {
result.computeStatusIfUnknown();
}
showResult(result);
statModel.reset();
campaignModel.reset();
target.add(get(createComponentPath(ID_MAIN_FORM)));
target.add((Component) getOutcomesTable()); // ???
target.add(getFeedbackPanel());
}
private ObjectQuery createCaseQuery() {
ObjectQuery query = new ObjectQuery();
return query;
}
private Table getOutcomesTable() {
return (Table) get(createComponentPath(ID_MAIN_FORM, ID_OUTCOMES_TABLE));
}
String getCampaignHandlerUri() {
return campaignModel.getObject().getHandlerUri();
}
}