/*
* 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.objectdetails;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
import javax.xml.namespace.QName;
import com.evolveum.midpoint.common.refinery.RefinedResourceSchemaImpl;
import com.evolveum.midpoint.web.component.prism.*;
import com.evolveum.midpoint.xml.ns._public.common.common_3.*;
import org.apache.commons.lang.Validate;
import org.apache.wicket.AttributeModifier;
import org.apache.wicket.ajax.AjaxRequestTarget;
import org.apache.wicket.ajax.markup.html.form.AjaxCheckBox;
import org.apache.wicket.extensions.ajax.markup.html.modal.ModalWindow;
import org.apache.wicket.markup.html.WebMarkupContainer;
import org.apache.wicket.markup.html.list.ListItem;
import org.apache.wicket.markup.html.list.ListView;
import org.apache.wicket.markup.html.panel.Panel;
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 com.evolveum.midpoint.common.refinery.RefinedObjectClassDefinition;
import com.evolveum.midpoint.common.refinery.RefinedResourceSchema;
import com.evolveum.midpoint.gui.api.component.ObjectBrowserPanel;
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.prism.PrismObjectDefinition;
import com.evolveum.midpoint.prism.PrismPropertyDefinition;
import com.evolveum.midpoint.prism.PrismPropertyValue;
import com.evolveum.midpoint.prism.PrismReferenceDefinition;
import com.evolveum.midpoint.prism.path.ItemPath;
import com.evolveum.midpoint.schema.constants.SchemaConstants;
import com.evolveum.midpoint.schema.result.OperationResult;
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.dialog.ConfirmationPanel;
import com.evolveum.midpoint.web.component.dialog.Popupable;
import com.evolveum.midpoint.web.component.form.Form;
import com.evolveum.midpoint.web.component.menu.cog.InlineMenu;
import com.evolveum.midpoint.web.component.menu.cog.InlineMenuItem;
import com.evolveum.midpoint.web.component.menu.cog.InlineMenuItemAction;
import com.evolveum.midpoint.web.component.util.ObjectWrapperUtil;
import com.evolveum.midpoint.web.component.util.VisibleEnableBehaviour;
import com.evolveum.midpoint.web.page.admin.PageAdminFocus;
import com.evolveum.midpoint.web.page.admin.users.dto.FocusSubwrapperDto;
import com.evolveum.midpoint.web.page.admin.users.dto.UserDtoStatus;
import com.evolveum.midpoint.web.resource.img.ImgResources;
/**
* @author semancik
*/
public class FocusProjectionsTabPanel<F extends FocusType> extends AbstractObjectTabPanel<F> {
private static final long serialVersionUID = 1L;
private static final String ID_SHADOW_LIST = "shadowList";
private static final String ID_SHADOWS = "shadows";
private static final String ID_SHADOW_HEADER = "shadowHeader";
private static final String ID_SHADOW = "shadow";
private static final String ID_SHADOW_MENU = "shadowMenu";
private static final String ID_SHADOW_CHECK_ALL = "shadowCheckAll";
private static final String MODAL_ID_RESOURCE = "resourcePopup";
private static final Trace LOGGER = TraceManager.getTrace(FocusProjectionsTabPanel.class);
private LoadableModel<List<FocusSubwrapperDto<ShadowType>>> projectionModel;
public FocusProjectionsTabPanel(String id, Form mainForm, LoadableModel<ObjectWrapper<F>> focusModel,
LoadableModel<List<FocusSubwrapperDto<ShadowType>>> projectionModel, PageBase page) {
super(id, mainForm, focusModel, page);
Validate.notNull(projectionModel, "Null projection model");
this.projectionModel = projectionModel;
initLayout(page);
}
private void initLayout(final PageBase page) {
final WebMarkupContainer shadows = new WebMarkupContainer(ID_SHADOWS);
shadows.setOutputMarkupId(true);
add(shadows);
InlineMenu accountMenu = new InlineMenu(ID_SHADOW_MENU, new Model((Serializable) createShadowMenu()));
accountMenu.setVisible(!getObjectWrapper().isReadonly());
shadows.add(accountMenu);
final ListView<FocusSubwrapperDto<ShadowType>> projectionList = new ListView<FocusSubwrapperDto<ShadowType>>(
ID_SHADOW_LIST, projectionModel) {
private static final long serialVersionUID = 1L;
@Override
protected void populateItem(final ListItem<FocusSubwrapperDto<ShadowType>> item) {
PackageResourceReference packageRef;
final FocusSubwrapperDto<ShadowType> dto = item.getModelObject();
final PropertyModel<ObjectWrapper<F>> objectWrapperModel = new PropertyModel<ObjectWrapper<F>>(
item.getModel(), "object");
final Panel shadowPanel;
if (dto.isLoadedOK()) {
packageRef = new PackageResourceReference(ImgResources.class, ImgResources.HDD_PRISM);
shadowPanel = new PrismObjectPanel<F>(ID_SHADOW,
new PropertyModel<ObjectWrapper<F>>(item.getModel(), "object"), packageRef,
getMainForm(), getPageBase());
} else {
shadowPanel = new SimpleErrorPanel<ShadowType>(ID_SHADOW, item.getModel()) {
private static final long serialVersionUID = 1L;
@Override
public void onShowMorePerformed(AjaxRequestTarget target) {
OperationResult fetchResult = dto.getResult();
if (fetchResult != null) {
showResult(fetchResult);
target.add(page.getFeedbackPanel());
}
}
};
}
shadowPanel.setOutputMarkupId(true);
shadowPanel.add(new VisibleEnableBehaviour() {
private static final long serialVersionUID = 1L;
@Override
public boolean isVisible() {
FocusSubwrapperDto<ShadowType> shadowWrapperDto = item.getModelObject();
ObjectWrapper<ShadowType> shadowWrapper = shadowWrapperDto.getObject();
return !shadowWrapper.isMinimalized();
}
});
item.add(shadowPanel);
CheckTableHeader<F> shadowHeader = new CheckTableHeader<F>(ID_SHADOW_HEADER,
objectWrapperModel) {
private static final long serialVersionUID = 1L;
@Override
protected void onClickPerformed(AjaxRequestTarget target) {
super.onClickPerformed(target);
onExpandCollapse(target, item.getModel());
target.add(shadows);
}
};
if (item.getModel().getObject().getStatus().equals(UserDtoStatus.DELETE)) {
shadowHeader.add(new AttributeModifier("class", "box-header with-border delete"));
}
item.add(shadowHeader);
}
};
AjaxCheckBox accountCheckAll = new AjaxCheckBox(ID_SHADOW_CHECK_ALL, new Model()) {
private static final long serialVersionUID = 1L;
@Override
protected void onUpdate(AjaxRequestTarget target) {
for (FocusSubwrapperDto<ShadowType> dto : projectionList.getModelObject()) {
if (dto.isLoadedOK()) {
ObjectWrapper<ShadowType> accModel = dto.getObject();
accModel.setSelected(getModelObject());
}
}
target.add(shadows);
}
};
shadows.add(accountCheckAll);
shadows.add(projectionList);
}
private void onExpandCollapse(AjaxRequestTarget target, IModel<FocusSubwrapperDto<ShadowType>> dtoModel) {
FocusSubwrapperDto<ShadowType> shadowWrapperDto = dtoModel.getObject();
ObjectWrapper<ShadowType> shadowWrapper = shadowWrapperDto.getObject();
if (shadowWrapper.isMinimalized()) {
return;
}
if (WebModelServiceUtils.isNoFetch(shadowWrapper.getLoadOptions())) {
((PageAdminFocus) getPage()).loadFullShadow(shadowWrapperDto);
}
}
private void addSelectedAccountPerformed(AjaxRequestTarget target, List<ResourceType> newResources) {
getPageBase().hideMainPopup(target);
if (newResources.isEmpty()) {
warn(getString("pageUser.message.noResourceSelected"));
return;
}
for (ResourceType resource : newResources) {
try {
ShadowType shadow = new ShadowType();
shadow.setResource(resource);
RefinedResourceSchema refinedSchema = RefinedResourceSchemaImpl.getRefinedSchema(
resource.asPrismObject(), LayerType.PRESENTATION, getPrismContext());
if (refinedSchema == null) {
error(getString("pageAdminFocus.message.couldntCreateAccountNoSchema",
resource.getName()));
continue;
}
if (LOGGER.isTraceEnabled()) {
LOGGER.trace("Refined schema for {}\n{}", resource, refinedSchema.debugDump());
}
RefinedObjectClassDefinition accountDefinition = refinedSchema
.getDefaultRefinedDefinition(ShadowKindType.ACCOUNT);
if (accountDefinition == null) {
error(getString("pageAdminFocus.message.couldntCreateAccountNoAccountSchema",
resource.getName()));
continue;
}
QName objectClass = accountDefinition.getObjectClassDefinition().getTypeName();
shadow.setObjectClass(objectClass);
getPrismContext().adopt(shadow);
ObjectWrapper<ShadowType> wrapper = ObjectWrapperUtil.createObjectWrapper(
WebComponentUtil.getOrigStringFromPoly(resource.getName()), null,
shadow.asPrismObject(), ContainerStatus.ADDING, getPageBase());
if (wrapper.getResult() != null
&& !WebComponentUtil.isSuccessOrHandledError(wrapper.getResult())) {
showResult(wrapper.getResult(), false);
}
wrapper.setShowEmpty(true);
wrapper.setMinimalized(true);
projectionModel.getObject().add(new FocusSubwrapperDto(wrapper, UserDtoStatus.ADD));
} catch (Exception ex) {
error(getString("pageAdminFocus.message.couldntCreateAccount", resource.getName(),
ex.getMessage()));
LoggingUtils.logUnexpectedException(LOGGER, "Couldn't create account", ex);
}
}
target.add(get(ID_SHADOWS));
}
private List<InlineMenuItem> createShadowMenu() {
List<InlineMenuItem> items = new ArrayList<InlineMenuItem>();
PrismObjectDefinition def = getObjectWrapper().getObject().getDefinition();
PrismReferenceDefinition ref = def.findReferenceDefinition(UserType.F_LINK_REF);
InlineMenuItem item;
if (ref.canRead() && ref.canAdd()) {
item = new InlineMenuItem(createStringResource("pageAdminFocus.button.addShadow"),
new InlineMenuItemAction() {
private static final long serialVersionUID = 1L;
@Override
public void onClick(AjaxRequestTarget target) {
List<QName> supportedTypes = new ArrayList<>(1);
supportedTypes.add(ResourceType.COMPLEX_TYPE);
PageBase pageBase = FocusProjectionsTabPanel.this.getPageBase();
ObjectBrowserPanel<ResourceType> resourceSelectionPanel = new ObjectBrowserPanel<ResourceType>(
pageBase.getMainPopupBodyId(), ResourceType.class, supportedTypes, true,
pageBase) {
@Override
protected void addPerformed(AjaxRequestTarget target, QName type,
List<ResourceType> selected) {
// TODO Auto-generated method stub
FocusProjectionsTabPanel.this.addSelectedAccountPerformed(target,
selected);
}
};
resourceSelectionPanel.setOutputMarkupId(true);
pageBase.showMainPopup(resourceSelectionPanel,
target);
}
});
items.add(item);
items.add(new InlineMenuItem());
}
PrismPropertyDefinition prop = def
.findPropertyDefinition(SchemaConstants.PATH_ACTIVATION_ADMINISTRATIVE_STATUS);
if (prop.canRead() && prop.canModify()) {
item = new InlineMenuItem(createStringResource("pageAdminFocus.button.enable"),
new InlineMenuItemAction() {
private static final long serialVersionUID = 1L;
@Override
public void onClick(AjaxRequestTarget target) {
updateShadowActivation(target, getSelectedProjections(projectionModel), true);
}
});
items.add(item);
item = new InlineMenuItem(createStringResource("pageAdminFocus.button.disable"),
new InlineMenuItemAction() {
/**
*
*/
private static final long serialVersionUID = 1L;
@Override
public void onClick(AjaxRequestTarget target) {
updateShadowActivation(target, getSelectedProjections(projectionModel), false);
}
});
items.add(item);
}
if (ref.canRead() && ref.canAdd()) {
item = new InlineMenuItem(createStringResource("pageAdminFocus.button.unlink"),
new InlineMenuItemAction() {
private static final long serialVersionUID = 1L;
@Override
public void onClick(AjaxRequestTarget target) {
unlinkProjectionPerformed(target, projectionModel,
getSelectedProjections(projectionModel), ID_SHADOWS);
}
});
items.add(item);
}
prop = def.findPropertyDefinition(SchemaConstants.PATH_ACTIVATION_LOCKOUT_STATUS);
if (prop.canRead() && prop.canModify()) {
item = new InlineMenuItem(createStringResource("pageAdminFocus.button.unlock"),
new InlineMenuItemAction() {
private static final long serialVersionUID = 1L;
@Override
public void onClick(AjaxRequestTarget target) {
unlockShadowPerformed(target, projectionModel,
getSelectedProjections(projectionModel));
}
});
items.add(item);
}
prop = def.findPropertyDefinition(SchemaConstants.PATH_ACTIVATION_ADMINISTRATIVE_STATUS);
if (prop.canRead() && prop.canModify()) {
items.add(new InlineMenuItem());
item = new InlineMenuItem(createStringResource("pageAdminFocus.button.delete"),
new InlineMenuItemAction() {
private static final long serialVersionUID = 1L;
@Override
public void onClick(AjaxRequestTarget target) {
deleteProjectionPerformed(target, projectionModel);
}
});
items.add(item);
}
return items;
}
private List<FocusSubwrapperDto<ShadowType>> getSelectedProjections(
IModel<List<FocusSubwrapperDto<ShadowType>>> projectionModel) {
List<FocusSubwrapperDto<ShadowType>> selected = new ArrayList<>();
List<FocusSubwrapperDto<ShadowType>> all = projectionModel.getObject();
for (FocusSubwrapperDto<ShadowType> shadow : all) {
if (shadow.isLoadedOK() && shadow.getObject().isSelected()) {
selected.add(shadow);
}
}
return selected;
}
private void deleteProjectionPerformed(AjaxRequestTarget target,
IModel<List<FocusSubwrapperDto<ShadowType>>> model) {
if (!isAnyProjectionSelected(target, model)) {
return;
}
showModalWindow(getDeleteProjectionPopupContent(),
target);
}
private boolean isAnyProjectionSelected(AjaxRequestTarget target,
IModel<List<FocusSubwrapperDto<ShadowType>>> model) {
List<FocusSubwrapperDto<ShadowType>> selected = getSelectedProjections(model);
if (selected.isEmpty()) {
warn(getString("pageAdminFocus.message.noAccountSelected"));
target.add(getFeedbackPanel());
return false;
}
return true;
}
private void updateShadowActivation(AjaxRequestTarget target,
List<FocusSubwrapperDto<ShadowType>> accounts, boolean enabled) {
if (!isAnyProjectionSelected(target, projectionModel)) {
return;
}
for (FocusSubwrapperDto<ShadowType> account : accounts) {
if (!account.isLoadedOK()) {
continue;
}
ObjectWrapper<ShadowType> wrapper = account.getObject();
ContainerWrapper<ActivationType> activation = wrapper
.findContainerWrapper(new ItemPath(ShadowType.F_ACTIVATION));
if (activation == null) {
warn(getString("pageAdminFocus.message.noActivationFound", wrapper.getDisplayName()));
continue;
}
PropertyWrapper enabledProperty = (PropertyWrapper) activation
.findPropertyWrapper(ActivationType.F_ADMINISTRATIVE_STATUS);
if (enabledProperty == null || enabledProperty.getValues().size() != 1) {
warn(getString("pageAdminFocus.message.noEnabledPropertyFound", wrapper.getDisplayName()));
continue;
}
ValueWrapper value = (ValueWrapper) enabledProperty.getValues().get(0);
ActivationStatusType status = enabled ? ActivationStatusType.ENABLED
: ActivationStatusType.DISABLED;
((PrismPropertyValue) value.getValue()).setValue(status);
wrapper.setSelected(false);
}
target.add(getFeedbackPanel(), get(createComponentPath(ID_SHADOWS)));
}
private void unlockShadowPerformed(AjaxRequestTarget target,
IModel<List<FocusSubwrapperDto<ShadowType>>> model,
List<FocusSubwrapperDto<ShadowType>> selected) {
if (!isAnyProjectionSelected(target, model)) {
return;
}
for (FocusSubwrapperDto<ShadowType> account : selected) {
if (!account.isLoadedOK()) {
continue;
}
ObjectWrapper<ShadowType> wrapper = account.getObject();
wrapper.setSelected(false);
ContainerWrapper<ActivationType> activation = wrapper.findContainerWrapper(new ItemPath(ShadowType.F_ACTIVATION));
if (activation == null) {
warn(getString("pageAdminFocus.message.noActivationFound", wrapper.getDisplayName()));
continue;
}
PropertyWrapper lockedProperty = activation.findPropertyWrapper(ActivationType.F_LOCKOUT_STATUS);
if (lockedProperty == null || lockedProperty.getValues().size() != 1) {
warn(getString("pageAdminFocus.message.noLockoutStatusPropertyFound", wrapper.getDisplayName()));
continue;
}
ValueWrapper value = (ValueWrapper) lockedProperty.getValues().get(0);
((PrismPropertyValue) value.getValue()).setValue(LockoutStatusType.NORMAL);
info(getString("pageAdminFocus.message.unlocked", wrapper.getDisplayName())); // TODO only for really unlocked accounts
}
target.add(getFeedbackPanel(), get(createComponentPath(ID_SHADOWS)));
}
private void unlinkProjectionPerformed(AjaxRequestTarget target,
IModel<List<FocusSubwrapperDto<ShadowType>>> model, List<FocusSubwrapperDto<ShadowType>> selected,
String componentPath) {
if (!isAnyProjectionSelected(target, model)) {
return;
}
for (FocusSubwrapperDto projection : selected) {
if (UserDtoStatus.ADD.equals(projection.getStatus())) {
continue;
}
projection.setStatus(UserDtoStatus.UNLINK);
}
target.add(get(createComponentPath(componentPath)));
}
private Popupable getDeleteProjectionPopupContent() {
ConfirmationPanel dialog = new ConfirmationPanel(getPageBase().getMainPopupBodyId(),
new AbstractReadOnlyModel<String>() {
private static final long serialVersionUID = 1L;
@Override
public String getObject() {
return createStringResource("pageAdminFocus.message.deleteAccountConfirm",
getSelectedProjections(projectionModel).size()).getString();
}
}) {
private static final long serialVersionUID = 1L;
@Override
public void yesPerformed(AjaxRequestTarget target) {
ModalWindow modalWindow = findParent(ModalWindow.class);
if (modalWindow != null) {
modalWindow.close(target);
deleteAccountConfirmedPerformed(target, getSelectedProjections(projectionModel));
}
}
};
return dialog;
}
private void deleteAccountConfirmedPerformed(AjaxRequestTarget target,
List<FocusSubwrapperDto<ShadowType>> selected) {
List<FocusSubwrapperDto<ShadowType>> accounts = projectionModel.getObject();
for (FocusSubwrapperDto<ShadowType> account : selected) {
if (UserDtoStatus.ADD.equals(account.getStatus())) {
accounts.remove(account);
} else {
account.setStatus(UserDtoStatus.DELETE);
}
}
target.add(get(createComponentPath(ID_SHADOWS)));
}
}