/*
* 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.component.assignment;
import com.evolveum.midpoint.common.refinery.RefinedObjectClassDefinition;
import com.evolveum.midpoint.common.refinery.RefinedResourceSchema;
import com.evolveum.midpoint.common.refinery.RefinedResourceSchemaImpl;
import com.evolveum.midpoint.gui.api.GuiStyleConstants;
import com.evolveum.midpoint.gui.api.component.BasePanel;
import com.evolveum.midpoint.gui.api.component.objecttypeselect.ObjectTypeSelectPanel;
import com.evolveum.midpoint.gui.api.component.togglebutton.ToggleIconButton;
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.api.util.WebModelServiceUtils;
import com.evolveum.midpoint.model.api.ModelService;
import com.evolveum.midpoint.prism.*;
import com.evolveum.midpoint.prism.path.ItemPath;
import com.evolveum.midpoint.prism.query.ObjectQuery;
import com.evolveum.midpoint.prism.query.builder.QueryBuilder;
import com.evolveum.midpoint.schema.GetOperationOptions;
import com.evolveum.midpoint.schema.SelectorOptions;
import com.evolveum.midpoint.schema.result.OperationResult;
import com.evolveum.midpoint.security.api.ItemSecurityDecisions;
import com.evolveum.midpoint.task.api.Task;
import com.evolveum.midpoint.util.MiscUtil;
import com.evolveum.midpoint.util.exception.CommunicationException;
import com.evolveum.midpoint.util.exception.ConfigurationException;
import com.evolveum.midpoint.util.exception.ObjectNotFoundException;
import com.evolveum.midpoint.util.exception.SchemaException;
import com.evolveum.midpoint.util.exception.SecurityViolationException;
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.component.DateInput;
import com.evolveum.midpoint.web.component.input.DropDownChoicePanel;
import com.evolveum.midpoint.web.component.prism.InputPanel;
import com.evolveum.midpoint.web.component.util.VisibleEnableBehaviour;
import com.evolveum.midpoint.web.page.admin.configuration.component.ChooseTypePanel;
import com.evolveum.midpoint.web.page.admin.configuration.component.EmptyOnBlurAjaxFormUpdatingBehaviour;
import com.evolveum.midpoint.web.page.admin.dto.ObjectViewDto;
import com.evolveum.midpoint.web.page.admin.users.component.AssignmentsPreviewDto;
import com.evolveum.midpoint.web.page.admin.users.dto.UserDtoStatus;
import com.evolveum.midpoint.xml.ns._public.common.common_3.*;
import com.evolveum.prism.xml.ns._public.types_3.ItemPathType;
import org.apache.wicket.AttributeModifier;
import org.apache.wicket.Component;
import org.apache.wicket.ajax.AjaxRequestTarget;
import org.apache.wicket.ajax.form.AjaxFormComponentUpdatingBehavior;
import org.apache.wicket.ajax.markup.html.AjaxLink;
import org.apache.wicket.ajax.markup.html.form.AjaxCheckBox;
import org.apache.wicket.markup.head.CssHeaderItem;
import org.apache.wicket.markup.head.IHeaderResponse;
import org.apache.wicket.markup.html.WebMarkupContainer;
import org.apache.wicket.markup.html.basic.Label;
import org.apache.wicket.markup.html.form.FormComponent;
import org.apache.wicket.markup.html.form.TextArea;
import org.apache.wicket.markup.html.list.ListItem;
import org.apache.wicket.markup.html.list.ListView;
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.resource.PackageResourceReference;
import org.apache.wicket.util.visit.IVisit;
import org.apache.wicket.util.visit.IVisitor;
import javax.xml.datatype.XMLGregorianCalendar;
import javax.xml.namespace.QName;
import java.util.*;
/**
* @author lazyman
*/
public class AssignmentEditorPanel extends BasePanel<AssignmentEditorDto> {
private static final long serialVersionUID = 1L;
private static final Trace LOGGER = TraceManager.getTrace(AssignmentEditorPanel.class);
private static final String DOT_CLASS = AssignmentEditorPanel.class.getName() + ".";
private static final String OPERATION_LOAD_OBJECT = DOT_CLASS + "loadObject";
private static final String OPERATION_LOAD_RESOURCE = DOT_CLASS + "loadResource";
private static final String OPERATION_LOAD_ATTRIBUTES = DOT_CLASS + "loadAttributes";
private static final String OPERATION_LOAD_TARGET_OBJECT = DOT_CLASS + "loadItemSecurityDecisions";
private static final String ID_HEADER_ROW = "headerRow";
private static final String ID_SELECTED = "selected";
private static final String ID_TYPE_IMAGE = "typeImage";
private static final String ID_NAME_LABEL = "nameLabel";
private static final String ID_NAME = "name";
private static final String ID_ACTIVATION = "activation";
private static final String ID_ACTIVATION_BLOCK = "activationBlock";
private static final String ID_EXPAND = "expand";
protected static final String ID_BODY = "body";
private static final String ID_DESCRIPTION = "description";
private static final String ID_RELATION_CONTAINER = "relationContainer";
private static final String ID_FOCUS_TYPE = "focusType";
private static final String ID_FOCUS_TYPE_CONTAINER = "focusTypeContainer";
protected static final String ID_RELATION = "relation";
private static final String ID_RELATION_LABEL = "relationLabel";
private static final String ID_ADMINISTRATIVE_STATUS = "administrativeStatus";
private static final String ID_VALID_FROM = "validFrom";
private static final String ID_VALID_TO = "validTo";
private static final String ID_SHOW_EMPTY = "showEmpty";
private static final String ID_SHOW_EMPTY_LABEL = "showEmptyLabel";
private static final String ID_ATTRIBUTES = "attributes";
private static final String ID_ATTRIBUTE = "attribute";
private static final String ID_AC_ATTRIBUTE = "acAttribute";
private static final String ID_TARGET = "target";
private static final String ID_TARGET_CONTAINER = "targetContainer";
private static final String ID_CONSTRUCTION_CONTAINER = "constructionContainer";
private static final String ID_CONTAINER_TENANT_REF = "tenantRefContainer";
private static final String ID_TENANT_CHOOSER = "tenantRefChooser";
private static final String ID_CONTAINER_ORG_REF = "orgRefContainer";
private static final String ID_ORG_CHOOSER = "orgRefChooser";
private static final String ID_BUTTON_SHOW_MORE = "errorLink";
private static final String ID_ERROR_ICON = "errorIcon";
private static final String ID_METADATA_CONTAINER = "metadataContainer";
private static final String ID_PROPERTY_CONTAINER = "propertyContainer";
private static final String ID_DESCRIPTION_CONTAINER = "descriptionContainer";
private static final String ID_ADMIN_STATUS_CONTAINER = "administrativeStatusContainer";
private static final String ID_VALID_FROM_CONTAINER = "validFromContainer";
private static final String ID_VALID_TO_CONTAINER = "validToContainer";
private IModel<List<ACAttributeDto>> attributesModel;
protected WebMarkupContainer headerRow;
protected PageBase pageBase;
protected List<AssignmentsPreviewDto> privilegesList;
protected boolean delegatedToMe;
private LoadableModel<ItemSecurityDecisions> decisionsModel;
public AssignmentEditorPanel(String id, IModel<AssignmentEditorDto> model, boolean delegatedToMe,
List<AssignmentsPreviewDto> privilegesList,
PageBase pageBase) {
super(id, model);
this.pageBase = pageBase;
this.privilegesList = privilegesList;
this.delegatedToMe = delegatedToMe;
initDecisionsModel();
initLayout();
}
public AssignmentEditorPanel(String id, IModel<AssignmentEditorDto> model) {
this(id, model, null);
}
public AssignmentEditorPanel(String id, IModel<AssignmentEditorDto> model, PageBase pageBase) {
super(id, model);
this.pageBase = pageBase;
attributesModel = new LoadableModel<List<ACAttributeDto>>(false) {
@Override
protected List<ACAttributeDto> load() {
return loadAttributes();
}
};
initDecisionsModel();
initLayout();
}
@Override
public void renderHead(IHeaderResponse response) {
super.renderHead(response);
response.render(CssHeaderItem.forReference(
new PackageResourceReference(AssignmentEditorPanel.class, "AssignmentEditorPanel.css")));
}
protected void initLayout() {
setOutputMarkupId(true);
headerRow = new WebMarkupContainer(ID_HEADER_ROW);
headerRow.add(AttributeModifier.append("class", createHeaderClassModel(getModel())));
headerRow.setOutputMarkupId(true);
add(headerRow);
initHeaderRow();
WebMarkupContainer body = new WebMarkupContainer(ID_BODY);
body.setOutputMarkupId(true);
body.add(new VisibleEnableBehaviour() {
@Override
public boolean isVisible() {
AssignmentEditorDto editorDto = AssignmentEditorPanel.this.getModel().getObject();
return !editorDto.isMinimized();
}
});
add(body);
initBodyLayout(body);
}
protected void initHeaderRow(){
AjaxCheckBox selected = new AjaxCheckBox(ID_SELECTED,
new PropertyModel<Boolean>(getModel(), AssignmentEditorDto.F_SELECTED)) {
private static final long serialVersionUID = 1L;
@Override
protected void onUpdate(AjaxRequestTarget target) {
// do we want to update something?
}
};
selected.add(new VisibleEnableBehaviour(){
@Override
public boolean isVisible(){
return !getModel().getObject().isSimpleView();
}
});
headerRow.add(selected);
WebMarkupContainer typeImage = new WebMarkupContainer(ID_TYPE_IMAGE);
typeImage.add(AttributeModifier.append("class", createImageTypeModel(getModel())));
headerRow.add(typeImage);
Label errorIcon = new Label(ID_ERROR_ICON);
errorIcon.add(new VisibleEnableBehaviour() {
private static final long serialVersionUID = 1L;
@Override
public boolean isVisible() {
return !isTargetValid();
}
});
headerRow.add(errorIcon);
AjaxLink name = new AjaxLink(ID_NAME) {
private static final long serialVersionUID = 1L;
@Override
public void onClick(AjaxRequestTarget target) {
nameClickPerformed(target);
}
};
headerRow.add(name);
AjaxLink errorLink = new AjaxLink(ID_BUTTON_SHOW_MORE) {
private static final long serialVersionUID = 1L;
@Override
public void onClick(AjaxRequestTarget target) {
showErrorPerformed(target);
}
};
errorLink.add(new VisibleEnableBehaviour() {
private static final long serialVersionUID = 1L;
@Override
public boolean isVisible() {
return !isTargetValid();
}
});
headerRow.add(errorLink);
Label nameLabel = new Label(ID_NAME_LABEL, createAssignmentNameLabelModel(false));
nameLabel.setOutputMarkupId(true);
name.add(nameLabel);
Label activation = new Label(ID_ACTIVATION, createActivationModel());
headerRow.add(activation);
ToggleIconButton expandButton = new ToggleIconButton(ID_EXPAND, GuiStyleConstants.CLASS_ICON_EXPAND,
GuiStyleConstants.CLASS_ICON_COLLAPSE) {
private static final long serialVersionUID = 1L;
@Override
public void onClick(AjaxRequestTarget target) {
nameClickPerformed(target);
}
@Override
public boolean isOn() {
return !AssignmentEditorPanel.this.getModelObject().isMinimized();
}
};
expandButton.add(new VisibleEnableBehaviour(){
@Override
public boolean isVisible(){
return !getModel().getObject().isSimpleView();
}
});
headerRow.add(expandButton);
}
protected IModel<String> createAssignmentNameLabelModel(final boolean isManager) {
return new AbstractReadOnlyModel<String>() {
@Override
public String getObject() {
if (getModel() != null && getModel().getObject() != null) {
AssignmentEditorDto dto = getModelObject();
if (dto.getName() != null) {
StringBuilder name = new StringBuilder(dto.getName());
if (isManager) {
name.append(" - Manager");
}
return name.toString();
}
if (dto.getAltName() != null) {
return getString("AssignmentEditorPanel.name.focus");
}
}
return getString("AssignmentEditorPanel.name.noTarget");
}
};
}
private boolean isTargetValid() {
if (getModel() != null && getModel().getObject() != null) {
AssignmentEditorDto dto = getModelObject();
if (dto.getName() == null && dto.getAltName() == null) {
return false;
}
}
return true;
}
protected IModel<String> createHeaderClassModel(final IModel<AssignmentEditorDto> model) {
return new AbstractReadOnlyModel<String>() {
private static final long serialVersionUID = 1L;
@Override
public String getObject() {
AssignmentEditorDto dto = model.getObject();
return dto.getStatus().name().toLowerCase();
}
};
}
private IModel<String> createActivationModel() {
return new AbstractReadOnlyModel<String>() {
private static final long serialVersionUID = 1L;
@Override
public String getObject() {
AssignmentEditorDto dto = getModel().getObject();
ActivationType activation = dto.getActivation();
if (activation == null) {
return "-";
}
ActivationStatusType status = activation.getAdministrativeStatus();
String strEnabled = createStringResource(status, "lower", "ActivationStatusType.null")
.getString();
if (activation.getValidFrom() != null && activation.getValidTo() != null) {
return getString("AssignmentEditorPanel.enabledFromTo", strEnabled,
MiscUtil.asDate(activation.getValidFrom()),
MiscUtil.asDate(activation.getValidTo()));
} else if (activation.getValidFrom() != null) {
return getString("AssignmentEditorPanel.enabledFrom", strEnabled,
MiscUtil.asDate(activation.getValidFrom()));
} else if (activation.getValidTo() != null) {
return getString("AssignmentEditorPanel.enabledTo", strEnabled,
MiscUtil.asDate(activation.getValidTo()));
}
return "-";
}
};
}
protected IModel<Date> createDateModel(final IModel<XMLGregorianCalendar> model) {
return new Model<Date>() {
@Override
public Date getObject() {
XMLGregorianCalendar calendar = model.getObject();
if (calendar == null) {
return null;
}
return MiscUtil.asDate(calendar);
}
@Override
public void setObject(Date object) {
if (object == null) {
model.setObject(null);
} else {
model.setObject(MiscUtil.asXMLGregorianCalendar(object));
}
}
};
}
protected void initBodyLayout(WebMarkupContainer body) {
WebMarkupContainer propertyContainer = new WebMarkupContainer(ID_PROPERTY_CONTAINER);
propertyContainer.setOutputMarkupId(true);
body.add(propertyContainer);
WebMarkupContainer descriptionContainer = new WebMarkupContainer(ID_DESCRIPTION_CONTAINER);
descriptionContainer.setOutputMarkupId(true);
descriptionContainer.add(new VisibleEnableBehaviour(){
private static final long serialVersionUID = 1L;
@Override
public boolean isVisible(){
return isItemAllowed(new ItemPath(FocusType.F_ASSIGNMENT, AssignmentType.F_DESCRIPTION));
}
});
body.add(descriptionContainer);
TextArea<String> description = new TextArea<>(ID_DESCRIPTION,
new PropertyModel<String>(getModel(), AssignmentEditorDto.F_DESCRIPTION));
description.add(new VisibleEnableBehaviour() {
private static final long serialVersionUID = 1L;
@Override
public boolean isEnabled() {
return getModel().getObject().isEditable();
}
});
descriptionContainer.add(description);
WebMarkupContainer relationContainer = new WebMarkupContainer(ID_RELATION_CONTAINER);
relationContainer.setOutputMarkupId(true);
relationContainer.setOutputMarkupPlaceholderTag(true);
relationContainer.add(new VisibleEnableBehaviour() {
@Override
public boolean isVisible() {
if (!isItemAllowed(new ItemPath(FocusType.F_ASSIGNMENT, AssignmentType.F_TARGET_REF,
ObjectReferenceType.F_RELATION))){
return false;
}
AssignmentEditorDto dto = getModel().getObject();
if (dto != null) {
if (AssignmentEditorDtoType.ORG_UNIT.equals(dto.getType()) ||
AssignmentEditorDtoType.SERVICE.equals(dto.getType()) ||
AssignmentEditorDtoType.ROLE.equals(dto.getType())) {
return true;
}
}
return false;
}
});
body.add(relationContainer);
addRelationDropDown(relationContainer);
WebMarkupContainer focusTypeContainer = new WebMarkupContainer(ID_FOCUS_TYPE_CONTAINER);
focusTypeContainer.setOutputMarkupId(true);
focusTypeContainer.add(new VisibleEnableBehaviour(){
private static final long serialVersionUID = 1L;
@Override
public boolean isVisible(){
return isItemAllowed(new ItemPath(FocusType.F_ASSIGNMENT, AssignmentType.F_FOCUS_TYPE));
}
});
body.add(focusTypeContainer);
ObjectTypeSelectPanel<FocusType> focusType = new ObjectTypeSelectPanel<>(ID_FOCUS_TYPE,
new PropertyModel<QName>(getModel(), AssignmentEditorDto.F_FOCUS_TYPE), FocusType.class);
focusTypeContainer.add(focusType);
Label relationLabel = new Label(ID_RELATION_LABEL, new AbstractReadOnlyModel<String>() {
@Override
public String getObject() {
if (getModel() == null || getModel().getObject() == null) {
return getString("AssignmentEditorPanel.relation.notSpecified");
}
AssignmentEditorDto object = getModel().getObject();
String propertyKey = RelationTypes.class.getSimpleName() + "." +
(object.getTargetRef() == null || object.getTargetRef().getRelation() == null ?
RelationTypes.MEMBER : RelationTypes.getRelationType(object.getTargetRef().getRelation()));
return createStringResource(propertyKey).getString();
}
});
relationLabel.setOutputMarkupId(true);
relationLabel.setOutputMarkupPlaceholderTag(true);
relationLabel.add(new VisibleEnableBehaviour() {
@Override
public boolean isVisible() {
return !isCreatingNewAssignment();
}
});
relationContainer.add(relationLabel);
WebMarkupContainer tenantRefContainer = createTenantContainer();
tenantRefContainer.add(new VisibleEnableBehaviour(){
private static final long serialVersionUID = 1L;
@Override
public boolean isVisible(){
return isItemAllowed(new ItemPath(FocusType.F_ASSIGNMENT, AssignmentType.F_TENANT_REF));
}
});
body.add(tenantRefContainer);
WebMarkupContainer orgRefContainer = createOrgContainer();
orgRefContainer.add(new VisibleEnableBehaviour(){
private static final long serialVersionUID = 1L;
@Override
public boolean isVisible(){
return isItemAllowed(new ItemPath(FocusType.F_ASSIGNMENT, AssignmentType.F_ORG_REF));
}
});
body.add(orgRefContainer);
propertyContainer.add(new VisibleEnableBehaviour(){
private static final long serialVersionUID = 1L;
@Override
public boolean isVisible(){
return isItemAllowed(new ItemPath(FocusType.F_ASSIGNMENT, AssignmentType.F_DESCRIPTION))
|| isItemAllowed(new ItemPath(FocusType.F_ASSIGNMENT, AssignmentType.F_TARGET_REF,
ObjectReferenceType.F_RELATION))
|| isItemAllowed(new ItemPath(FocusType.F_ASSIGNMENT, AssignmentType.F_FOCUS_TYPE))
|| isItemAllowed(new ItemPath(FocusType.F_ASSIGNMENT, AssignmentType.F_TENANT_REF))
|| isItemAllowed(new ItemPath(FocusType.F_ASSIGNMENT, AssignmentType.F_ORG_REF));
}
});
WebMarkupContainer activationBlock = new WebMarkupContainer(ID_ACTIVATION_BLOCK);
body.add(activationBlock);
WebMarkupContainer adminStatusContainer = new WebMarkupContainer(ID_ADMIN_STATUS_CONTAINER);
adminStatusContainer.setOutputMarkupId(true);
adminStatusContainer.add(new VisibleEnableBehaviour() {
private static final long serialVersionUID = 1L;
@Override
public boolean isVisible() {
return isItemAllowed(new ItemPath(FocusType.F_ASSIGNMENT, AssignmentType.F_ACTIVATION,
ActivationType.F_ADMINISTRATIVE_STATUS));
}
});
activationBlock.add(adminStatusContainer);
DropDownChoicePanel administrativeStatus = WebComponentUtil.createEnumPanel(
ActivationStatusType.class, ID_ADMINISTRATIVE_STATUS,
new PropertyModel<ActivationStatusType>(getModel(), AssignmentEditorDto.F_ACTIVATION + "."
+ ActivationType.F_ADMINISTRATIVE_STATUS.getLocalPart()),
this);
administrativeStatus.add(new VisibleEnableBehaviour(){
private static final long serialVersionUID = 1L;
@Override
public boolean isEnabled(){
return getModel().getObject().isEditable();
}
});
adminStatusContainer.add(administrativeStatus);
WebMarkupContainer validFromContainer = new WebMarkupContainer(ID_VALID_FROM_CONTAINER);
validFromContainer.setOutputMarkupId(true);
validFromContainer.add(new VisibleEnableBehaviour() {
private static final long serialVersionUID = 1L;
@Override
public boolean isVisible() {
return isItemAllowed(new ItemPath(FocusType.F_ASSIGNMENT, AssignmentType.F_ACTIVATION,
ActivationType.F_VALID_FROM));
}
});
activationBlock.add(validFromContainer);
DateInput validFrom = new DateInput(ID_VALID_FROM,
createDateModel(new PropertyModel<XMLGregorianCalendar>(getModel(),
AssignmentEditorDto.F_ACTIVATION + ".validFrom")));
validFrom.add(new VisibleEnableBehaviour(){
private static final long serialVersionUID = 1L;
@Override
public boolean isEnabled(){
return getModel().getObject().isEditable();
}
});
validFromContainer.add(validFrom);
WebMarkupContainer validToContainer = new WebMarkupContainer(ID_VALID_TO_CONTAINER);
validToContainer.setOutputMarkupId(true);
validToContainer.add(new VisibleEnableBehaviour() {
private static final long serialVersionUID = 1L;
@Override
public boolean isVisible() {
return isItemAllowed(new ItemPath(FocusType.F_ASSIGNMENT, AssignmentType.F_ACTIVATION,
ActivationType.F_VALID_TO));
}
});
activationBlock.add(validToContainer);
DateInput validTo = new DateInput(ID_VALID_TO,
createDateModel(new PropertyModel<XMLGregorianCalendar>(getModel(),
AssignmentEditorDto.F_ACTIVATION + ".validTo")));
validTo.add(new VisibleEnableBehaviour(){
private static final long serialVersionUID = 1L;
@Override
public boolean isEnabled(){
return getModel().getObject().isEditable();
}
});
validToContainer.add(validTo);
activationBlock.add(new VisibleEnableBehaviour() {
@Override
public boolean isVisible() {
// enabled activation in assignments for now.
return true;
}
});
WebMarkupContainer targetContainer = new WebMarkupContainer(ID_TARGET_CONTAINER);
targetContainer.add(new VisibleEnableBehaviour() {
@Override
public boolean isVisible() {
if (!isItemAllowed(new ItemPath(FocusType.F_ASSIGNMENT, AssignmentType.F_TARGET))){
return false;
}
AssignmentEditorDto dto = getModel().getObject();
return !AssignmentEditorDtoType.CONSTRUCTION.equals(dto.getType());
}
});
body.add(targetContainer);
Label target = new Label(ID_TARGET, createTargetModel());
targetContainer.add(target);
WebMarkupContainer constructionContainer = new WebMarkupContainer(ID_CONSTRUCTION_CONTAINER);
constructionContainer.add(new VisibleEnableBehaviour() {
@Override
public boolean isVisible() {
AssignmentEditorDto dto = getModel().getObject();
return AssignmentEditorDtoType.CONSTRUCTION.equals(dto.getType());
}
});
body.add(constructionContainer);
AjaxLink showEmpty = new AjaxLink(ID_SHOW_EMPTY) {
@Override
public void onClick(AjaxRequestTarget target) {
showEmptyPerformed(target);
}
};
constructionContainer.add(showEmpty);
Label showEmptyLabel = new Label(ID_SHOW_EMPTY_LABEL, createShowEmptyLabel());
showEmptyLabel.setOutputMarkupId(true);
showEmpty.add(showEmptyLabel);
initAttributesLayout(constructionContainer);
Component metadataPanel;
if (UserDtoStatus.ADD.equals(getModel().getObject().getStatus()) ||
getModelObject().getOldValue().asContainerable() == null){
metadataPanel = new WebMarkupContainer(ID_METADATA_CONTAINER);
} else {
metadataPanel = new MetadataPanel(ID_METADATA_CONTAINER, new AbstractReadOnlyModel<MetadataType>() {
@Override
public MetadataType getObject() {
return getModelObject().getOldValue().getValue().getMetadata();
}
}, "row");
}
metadataPanel.setOutputMarkupId(true);
metadataPanel.add(new VisibleEnableBehaviour(){
@Override
public boolean isVisible(){
return !UserDtoStatus.ADD.equals(getModel().getObject().getStatus());
}
});
body.add(metadataPanel);
addAjaxOnUpdateBehavior(body);
}
private void updateAssignmentName(AjaxRequestTarget target, Boolean isManager){
Label nameLabel = new Label(ID_NAME_LABEL, createAssignmentNameLabelModel(isManager));
nameLabel.setOutputMarkupId(true);
AjaxLink name = (AjaxLink) get(createComponentPath(ID_HEADER_ROW, ID_NAME));
name.addOrReplace(nameLabel);
target.add(name);
}
private WebMarkupContainer createTenantContainer() {
WebMarkupContainer tenantRefContainer = new WebMarkupContainer(ID_CONTAINER_TENANT_REF);
ChooseTypePanel tenantRef = new ChooseTypePanel(ID_TENANT_CHOOSER,
new PropertyModel<ObjectViewDto>(getModel(), AssignmentEditorDto.F_TENANT_REF)) {
@Override
protected ObjectQuery getChooseQuery() {
return QueryBuilder.queryFor(OrgType.class, getPageBase().getPrismContext())
.item(OrgType.F_TENANT).eq(true)
.build();
}
@Override
protected boolean isSearchEnabled() {
return true;
}
@Override
protected QName getSearchProperty() {
return OrgType.F_NAME;
}
};
tenantRef.setPanelEnabled(getModel().getObject().isEditable());
tenantRefContainer.add(tenantRef);
tenantRefContainer.add(new VisibleEnableBehaviour() {
@Override
public boolean isVisible() {
AssignmentEditorDto dto = getModel().getObject();
if (dto != null) {
if (AssignmentEditorDtoType.ROLE.equals(dto.getType())) {
return true;
}
}
return false;
}
});
return tenantRefContainer;
}
private WebMarkupContainer createOrgContainer() {
WebMarkupContainer tenantRefContainer = new WebMarkupContainer(ID_CONTAINER_ORG_REF);
ChooseTypePanel tenantRef = new ChooseTypePanel(ID_ORG_CHOOSER,
new PropertyModel<ObjectViewDto>(getModel(), AssignmentEditorDto.F_ORG_REF)) {
@Override
protected ObjectQuery getChooseQuery() {
return QueryBuilder.queryFor(OrgType.class, getPageBase().getPrismContext())
.item(OrgType.F_TENANT).eq(false)
.or().item(OrgType.F_TENANT).isNull()
.build();
}
@Override
protected boolean isSearchEnabled() {
return true;
}
@Override
protected QName getSearchProperty() {
return OrgType.F_NAME;
}
};
tenantRefContainer.add(tenantRef);
tenantRef.setEnabled(getModel().getObject().isEditable());
tenantRefContainer.add(new VisibleEnableBehaviour() {
@Override
public boolean isVisible() {
AssignmentEditorDto dto = getModel().getObject();
if (dto != null) {
if (AssignmentEditorDtoType.ROLE.equals(dto.getType())) {
return true;
}
}
return false;
}
});
return tenantRefContainer;
}
private void addAjaxOnBlurUpdateBehaviorToComponent(final Component component) {
component.setOutputMarkupId(true);
component.add(new AjaxFormComponentUpdatingBehavior("blur") {
@Override
protected void onUpdate(AjaxRequestTarget target) {
}
});
}
protected void addAjaxOnUpdateBehavior(WebMarkupContainer container) {
container.visitChildren(new IVisitor<Component, Object>() {
@Override
public void component(Component component, IVisit<Object> objectIVisit) {
if (component instanceof InputPanel) {
addAjaxOnBlurUpdateBehaviorToComponent(((InputPanel) component).getBaseFormComponent());
} else if (component instanceof FormComponent) {
addAjaxOnBlurUpdateBehaviorToComponent(component);
}
}
});
}
private void initAttributesLayout(WebMarkupContainer constructionContainer) {
WebMarkupContainer attributes = new WebMarkupContainer(ID_ATTRIBUTES);
attributes.setOutputMarkupId(true);
attributes.add(new VisibleEnableBehaviour() {
@Override
public boolean isVisible() {
AssignmentEditorDto dto = getModel().getObject();
return AssignmentEditorDtoType.CONSTRUCTION.equals(dto.getType());
}
});
attributes.setEnabled(getModel().getObject().isEditable());
constructionContainer.add(attributes);
ListView<ACAttributeDto> attribute = new ListView<ACAttributeDto>(ID_ATTRIBUTE, attributesModel) {
@Override
protected void populateItem(ListItem<ACAttributeDto> listItem) {
final IModel<ACAttributeDto> attrModel = listItem.getModel();
ACAttributePanel acAttribute = new ACAttributePanel(ID_AC_ATTRIBUTE, attrModel, ignoreMandatoryAttributes());
acAttribute.setRenderBodyOnly(true);
listItem.add(acAttribute);
listItem.setOutputMarkupId(true);
listItem.add(new VisibleEnableBehaviour() {
@Override
public boolean isVisible() {
AssignmentEditorDto editorDto = AssignmentEditorPanel.this.getModel().getObject();
if (editorDto.isShowEmpty()) {
return true;
}
ACAttributeDto dto = attrModel.getObject();
return !dto.isEmpty();
}
});
}
};
attributes.add(attribute);
// todo extension
}
private IModel<String> createShowEmptyLabel() {
return new AbstractReadOnlyModel<String>() {
@Override
public String getObject() {
AssignmentEditorDto dto = AssignmentEditorPanel.this.getModel().getObject();
if (dto.isShowEmpty()) {
return getString("AssignmentEditorPanel.hideEmpty");
} else {
return getString("AssignmentEditorPanel.showEmpty");
}
}
};
}
private void showEmptyPerformed(AjaxRequestTarget target) {
AssignmentEditorDto dto = AssignmentEditorPanel.this.getModel().getObject();
dto.setShowEmpty(!dto.isShowEmpty());
WebMarkupContainer parent = (WebMarkupContainer) get(
createComponentPath(ID_BODY, ID_CONSTRUCTION_CONTAINER));
target.add(parent.get(ID_ATTRIBUTES),
parent.get(createComponentPath(ID_SHOW_EMPTY, ID_SHOW_EMPTY_LABEL)),
getPageBase().getFeedbackPanel());
}
private List<ACAttributeDto> loadAttributes() {
AssignmentEditorDto dto = getModel().getObject();
OperationResult result = new OperationResult(OPERATION_LOAD_ATTRIBUTES);
List<ACAttributeDto> attributes = new ArrayList<>();
try {
ConstructionType construction = WebComponentUtil.getContainerValue(dto.getOldValue(),
AssignmentType.F_CONSTRUCTION, ConstructionType.class);
if (construction == null) {
return attributes;
}
PrismObject<ResourceType> resource = construction.getResource() != null
? construction.getResource().asPrismObject() : null;
if (resource == null) {
resource = getReference(construction.getResourceRef(), result);
}
PrismContext prismContext = getPageBase().getPrismContext();
RefinedResourceSchema refinedSchema = RefinedResourceSchemaImpl.getRefinedSchema(resource,
LayerType.PRESENTATION, prismContext);
RefinedObjectClassDefinition objectClassDefinition = refinedSchema
.getRefinedDefinition(ShadowKindType.ACCOUNT, construction.getIntent());
if (objectClassDefinition == null) {
return attributes;
}
PrismContainerDefinition definition = objectClassDefinition
.toResourceAttributeContainerDefinition();
if (LOGGER.isTraceEnabled()) {
LOGGER.trace("Refined definition for {}\n{}", construction, definition.debugDump());
}
List<ResourceAttributeDefinitionType> attrConstructions = construction.getAttribute();
Collection<ItemDefinition> definitions = definition.getDefinitions();
for (ItemDefinition attrDef : definitions) {
if (!(attrDef instanceof PrismPropertyDefinition)) {
// log skipping or something...
continue;
}
PrismPropertyDefinition propertyDef = (PrismPropertyDefinition) attrDef;
if (propertyDef.isOperational() || propertyDef.isIgnored()) {
continue;
}
attributes.add(ACAttributeDto.createACAttributeDto(propertyDef,
findOrCreateValueConstruction(propertyDef, attrConstructions), prismContext));
}
result.recordSuccess();
} catch (Exception ex) {
LoggingUtils.logUnexpectedException(LOGGER, "Exception occurred during assignment attribute loading", ex);
result.recordFatalError("Exception occurred during assignment attribute loading.", ex);
} finally {
result.recomputeStatus();
}
Collections.sort(attributes, new Comparator<ACAttributeDto>() {
@Override
public int compare(ACAttributeDto a1, ACAttributeDto a2) {
return String.CASE_INSENSITIVE_ORDER.compare(a1.getName(), a2.getName());
}
});
if (dto.getAttributes() != null && !dto.getAttributes().isEmpty()) {
for (ACAttributeDto assignmentAttribute : dto.getAttributes()) {
for (ACAttributeDto attributeDto : attributes){
if (attributeDto.getName().equals(assignmentAttribute.getName())){
attributes.set(attributes.indexOf(attributeDto), assignmentAttribute);
continue;
}
}
}
}
dto.setAttributes(attributes);
getPageBase().showResult(result, false);
return dto.getAttributes();
}
private PrismObject getReference(ObjectReferenceType ref, OperationResult result) {
OperationResult subResult = result.createSubresult(OPERATION_LOAD_RESOURCE);
subResult.addParam("targetRef", ref.getOid());
PrismObject target = null;
try {
Task task = getPageBase().createSimpleTask(OPERATION_LOAD_RESOURCE);
Class type = ObjectType.class;
if (ref.getType() != null) {
type = getPageBase().getPrismContext().getSchemaRegistry()
.determineCompileTimeClass(ref.getType());
}
target = getPageBase().getModelService().getObject(type, ref.getOid(), null, task, subResult);
subResult.recordSuccess();
} catch (Exception ex) {
LoggingUtils.logUnexpectedException(LOGGER, "Couldn't get account construction resource ref", ex);
subResult.recordFatalError("Couldn't get account construction resource ref.", ex);
}
return target;
}
private ResourceAttributeDefinitionType findOrCreateValueConstruction(PrismPropertyDefinition attrDef,
List<ResourceAttributeDefinitionType> attrConstructions) {
for (ResourceAttributeDefinitionType construction : attrConstructions) {
if (attrDef.getName().equals(construction.getRef())) {
return construction;
}
}
ResourceAttributeDefinitionType construction = new ResourceAttributeDefinitionType();
construction.setRef(new ItemPathType(new ItemPath(attrDef.getName())));
return construction;
}
protected IModel<String> createImageTypeModel(final IModel<AssignmentEditorDto> model) {
return new AbstractReadOnlyModel<String>() {
private static final long serialVersionUID = 1L;
@Override
public String getObject() {
AssignmentEditorDto assignmentEditorDto = model.getObject();
PrismObject targetObject = null;
try {
targetObject = getTargetObject(assignmentEditorDto);
} catch (Exception ex) {
LoggingUtils.logUnexpectedException(LOGGER, "Couldn't load object", ex);
// Otherwise ignore, will be pocessed by the fallback code
// below
}
if (targetObject == null) {
AssignmentEditorDtoType type = assignmentEditorDto.getType();
return type.getIconCssClass();
} else {
return WebComponentUtil.createDefaultIcon(targetObject);
}
}
};
}
protected void nameClickPerformed(AjaxRequestTarget target) {
AssignmentEditorDto dto = getModel().getObject();
boolean minimized = dto.isMinimized();
dto.setMinimized(!minimized);
target.add(this);
}
protected IModel<String> createTargetModel() {
return new LoadableModel<String>(false) {
private static final long serialVersionUID = 1L;
@Override
protected String load() {
AssignmentEditorDto dto = getModel().getObject();
PrismObject targetObject;
try {
targetObject = getTargetObject(dto);
} catch (Exception ex) {
LoggingUtils.logUnexpectedException(LOGGER, "Couldn't load object", ex);
return getString("AssignmentEditorPanel.loadError");
}
if (targetObject == null) {
return getString("AssignmentEditorPanel.undefined");
}
return WebComponentUtil.getName(targetObject);
}
};
}
private void addRelationDropDown(WebMarkupContainer relationContainer){
List<RelationTypes> availableRelations = getModelObject().getNotAssignedRelationsList();
DropDownChoicePanel relation = WebComponentUtil.createEnumPanel(RelationTypes.class, ID_RELATION,
getModelObject().isMultyAssignable() ?
WebComponentUtil.createReadonlyModelFromEnum(RelationTypes.class) : Model.ofList(availableRelations),
getRelationModel(availableRelations), this, false);
relation.setEnabled(getModel().getObject().isEditable());
relation.setOutputMarkupId(true);
relation.setOutputMarkupPlaceholderTag(true);
relation.add(new VisibleEnableBehaviour() {
@Override
public boolean isVisible() {
return isCreatingNewAssignment();
}
});
relationContainer.add(relation);
}
private IModel<RelationTypes> getRelationModel(List<RelationTypes> availableRelations){
return new IModel<RelationTypes>() {
@Override
public RelationTypes getObject() {
RelationTypes defaultRelation = RelationTypes.MEMBER;
if (!getModelObject().isMultyAssignable() &&
getModelObject().getAssignedRelationsList().contains(defaultRelation)){
defaultRelation = availableRelations.get(0);
}
if (getModelObject().getTargetRef() == null){
return defaultRelation;
}
return RelationTypes.getRelationType(getModelObject().getTargetRef().getRelation());
}
@Override
public void setObject(RelationTypes relationTypes) {
if (getModelObject().getTargetRef() != null){
getModelObject().getTargetRef().setRelation(relationTypes.getRelation());
}
}
@Override
public void detach() {
}
};
}
protected IModel<RelationTypes> getRelationModel(){
return new IModel<RelationTypes>() {
private static final long serialVersionUID = 1L;
@Override
public RelationTypes getObject() {
if (getModelObject().getTargetRef() == null) {
return RelationTypes.MEMBER;
}
return RelationTypes.getRelationType(getModelObject().getTargetRef().getRelation());
}
@Override
public void setObject(RelationTypes newValue) {
ObjectReferenceType ref = getModelObject().getTargetRef();
if (ref != null){
ref.setRelation(newValue.getRelation());
}
}
@Override
public void detach() {
}
};
}
private <O extends ObjectType> PrismObject<O> getTargetObject(AssignmentEditorDto dto)
throws ObjectNotFoundException, SchemaException, SecurityViolationException,
CommunicationException, ConfigurationException {
PrismContainerValue<AssignmentType> assignment = dto.getOldValue();
PrismReference targetRef = assignment.findReference(AssignmentType.F_TARGET_REF);
if (targetRef == null) {
return null;
}
PrismReferenceValue refValue = targetRef.getValue();
if (refValue != null && refValue.getObject() != null) {
PrismObject object = refValue.getObject();
return object;
}
String oid = targetRef.getOid();
OperationResult result = new OperationResult(OPERATION_LOAD_OBJECT);
PageBase page = getPageBase();
ModelService model = page.getMidpointApplication().getModel();
Task task = page.createSimpleTask(OPERATION_LOAD_OBJECT);
Collection<SelectorOptions<GetOperationOptions>> options = SelectorOptions
.createCollection(GetOperationOptions.createNoFetch());
Class<O> type = (Class<O>) ObjectType.class;
if (refValue.getTargetType() != null) {
type = getPageBase().getPrismContext().getSchemaRegistry()
.determineCompileTimeClass(refValue.getTargetType());
}
PrismObject<O> object = model.getObject(type, oid, options, task, result);
refValue.setObject(object);
return object;
}
private void showErrorPerformed(AjaxRequestTarget target) {
error(getString("AssignmentEditorPanel.targetError"));
target.add(getPageBase().getFeedbackPanel());
}
/**
* Override to provide the information if object that contains this
* assignment is being edited or created.
*/
protected boolean isCreatingNewAssignment() {
if (getModelObject() == null) {
return false;
}
return UserDtoStatus.ADD.equals(getModelObject().getStatus());
}
protected boolean ignoreMandatoryAttributes(){
return false;
}
private void initDecisionsModel(){
decisionsModel = new LoadableModel<ItemSecurityDecisions>(false) {
@Override
protected ItemSecurityDecisions load() {
return loadSecurityDecisions();
}
};
}
private boolean isItemAllowed(ItemPath itemPath){
ItemSecurityDecisions decisions = decisionsModel.getObject();
if (itemPath == null || decisions == null || decisions.getItemDecisionMap() == null
|| decisions.getItemDecisionMap().size() == 0){
return true;
}
Map<ItemPath, AuthorizationDecisionType> decisionsMap = decisions.getItemDecisionMap();
boolean isAllowed = false;
for (ItemPath path : decisionsMap.keySet()) {
if (path.equivalent(itemPath)
&& AuthorizationDecisionType.ALLOW.value().equals(decisionsMap.get(path).value())) {
return true;
}
}
return isAllowed;
}
private ItemSecurityDecisions loadSecurityDecisions(){
if (pageBase == null || getModelObject().getTargetRef() == null){
return null;
}
PrismObject<UserType> user = null;
List<PrismObject<UserType>> targetUserList = pageBase.getSessionStorage().getRoleCatalog().getTargetUserList();
if (targetUserList == null || targetUserList.size() == 0){
user = pageBase.loadUserSelf(pageBase);
} else {
user = targetUserList.get(0);
}
String targetObjectOid = getModelObject().getTargetRef().getOid();
Task task = pageBase.createSimpleTask(OPERATION_LOAD_TARGET_OBJECT);
OperationResult result = new OperationResult(OPERATION_LOAD_TARGET_OBJECT);
PrismObject<AbstractRoleType> targetRefObject = WebModelServiceUtils.loadObject(AbstractRoleType.class,
targetObjectOid, pageBase, task, result);
ItemSecurityDecisions decisions = null;
try{
decisions =
pageBase.getModelInteractionService().getAllowedRequestAssignmentItems(user, targetRefObject);
} catch (SchemaException|SecurityViolationException ex){
LoggingUtils.logUnexpectedException(LOGGER, "Couldn't load security decisions for assignment items.", ex);
}
return decisions;
}
}