/*
* 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.resources;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import javax.xml.namespace.QName;
import com.evolveum.midpoint.common.refinery.RefinedResourceSchemaImpl;
import com.evolveum.midpoint.prism.query.builder.QueryBuilder;
import com.evolveum.midpoint.web.session.SessionStorage;
import org.apache.commons.lang.StringUtils;
import org.apache.wicket.ajax.AjaxRequestTarget;
import org.apache.wicket.extensions.markup.html.repeater.data.grid.ICellPopulator;
import org.apache.wicket.extensions.markup.html.repeater.data.table.AbstractColumn;
import org.apache.wicket.extensions.markup.html.repeater.data.table.IColumn;
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.markup.html.panel.Panel;
import org.apache.wicket.markup.repeater.Item;
import org.apache.wicket.markup.repeater.RepeatingView;
import org.apache.wicket.model.AbstractReadOnlyModel;
import org.apache.wicket.model.IModel;
import org.apache.wicket.model.Model;
import org.apache.wicket.model.StringResourceModel;
import org.apache.wicket.model.util.ListModel;
import org.apache.wicket.request.mapper.parameter.PageParameters;
import com.evolveum.midpoint.common.refinery.RefinedObjectClassDefinition;
import com.evolveum.midpoint.common.refinery.RefinedResourceSchema;
import com.evolveum.midpoint.gui.api.GuiStyleConstants;
import com.evolveum.midpoint.gui.api.component.MainObjectListPanel;
import com.evolveum.midpoint.gui.api.component.ObjectBrowserPanel;
import com.evolveum.midpoint.gui.api.component.button.DropdownButtonDto;
import com.evolveum.midpoint.gui.api.component.button.DropdownButtonPanel;
import com.evolveum.midpoint.gui.api.component.result.OpResult;
import com.evolveum.midpoint.gui.api.component.result.OperationResultPanel;
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.ModelExecuteOptions;
import com.evolveum.midpoint.prism.PrismObject;
import com.evolveum.midpoint.prism.PrismObjectDefinition;
import com.evolveum.midpoint.prism.PrismProperty;
import com.evolveum.midpoint.prism.delta.ItemDelta;
import com.evolveum.midpoint.prism.delta.ObjectDelta;
import com.evolveum.midpoint.prism.delta.ReferenceDelta;
import com.evolveum.midpoint.prism.path.ItemPath;
import com.evolveum.midpoint.prism.query.AndFilter;
import com.evolveum.midpoint.prism.query.ObjectFilter;
import com.evolveum.midpoint.prism.query.ObjectQuery;
import com.evolveum.midpoint.prism.query.RefFilter;
import com.evolveum.midpoint.schema.GetOperationOptions;
import com.evolveum.midpoint.schema.RetrieveOption;
import com.evolveum.midpoint.schema.SelectorOptions;
import com.evolveum.midpoint.schema.constants.SchemaConstants;
import com.evolveum.midpoint.schema.processor.ResourceAttribute;
import com.evolveum.midpoint.schema.result.OperationResult;
import com.evolveum.midpoint.schema.util.ObjectQueryUtil;
import com.evolveum.midpoint.schema.util.ObjectTypeUtil;
import com.evolveum.midpoint.schema.util.ShadowUtil;
import com.evolveum.midpoint.task.api.Task;
import com.evolveum.midpoint.task.api.TaskCategory;
import com.evolveum.midpoint.util.exception.CommunicationException;
import com.evolveum.midpoint.util.exception.ConfigurationException;
import com.evolveum.midpoint.util.exception.ExpressionEvaluationException;
import com.evolveum.midpoint.util.exception.ObjectAlreadyExistsException;
import com.evolveum.midpoint.util.exception.ObjectNotFoundException;
import com.evolveum.midpoint.util.exception.PolicyViolationException;
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.data.BaseSortableDataProvider;
import com.evolveum.midpoint.web.component.data.SelectableBeanObjectDataProvider;
import com.evolveum.midpoint.web.component.data.column.ColumnMenuAction;
import com.evolveum.midpoint.web.component.data.column.ColumnTypeDto;
import com.evolveum.midpoint.web.component.data.column.ColumnUtils;
import com.evolveum.midpoint.web.component.data.column.InlineMenuHeaderColumn;
import com.evolveum.midpoint.web.component.data.column.LinkColumn;
import com.evolveum.midpoint.web.component.data.column.ObjectLinkColumn;
import com.evolveum.midpoint.web.component.dialog.ConfirmationPanel;
import com.evolveum.midpoint.web.component.menu.cog.InlineMenuItem;
import com.evolveum.midpoint.web.component.menu.cog.InlineMenuItemAction;
import com.evolveum.midpoint.web.component.search.Search;
import com.evolveum.midpoint.web.component.util.SelectableBean;
import com.evolveum.midpoint.web.component.util.VisibleEnableBehaviour;
import com.evolveum.midpoint.web.page.admin.configuration.component.HeaderMenuAction;
import com.evolveum.midpoint.web.page.admin.resources.ResourceContentTabPanel.Operation;
import com.evolveum.midpoint.web.page.admin.resources.content.PageAccount;
import com.evolveum.midpoint.web.page.admin.server.PageTaskAdd;
import com.evolveum.midpoint.web.session.UserProfileStorage.TableId;
import com.evolveum.midpoint.web.util.OnePageParameterEncoder;
import com.evolveum.midpoint.xml.ns._public.common.common_3.ActivationStatusType;
import com.evolveum.midpoint.xml.ns._public.common.common_3.FocusType;
import com.evolveum.midpoint.xml.ns._public.common.common_3.ObjectType;
import com.evolveum.midpoint.xml.ns._public.common.common_3.OperationResultType;
import com.evolveum.midpoint.xml.ns._public.common.common_3.ResourceType;
import com.evolveum.midpoint.xml.ns._public.common.common_3.ShadowKindType;
import com.evolveum.midpoint.xml.ns._public.common.common_3.ShadowType;
import com.evolveum.midpoint.xml.ns._public.common.common_3.TaskType;
import com.evolveum.midpoint.xml.ns._public.common.common_3.UserType;
/**
* Implementation classes : ResourceContentResourcePanel,
* ResourceContentRepositoryPanel
*
* @author katkav
* @author semancik
*/
public abstract class ResourceContentPanel extends Panel {
private static final long serialVersionUID = 1L;
private static final Trace LOGGER = TraceManager.getTrace(ResourceContentPanel.class);
private static final String DOT_CLASS = ResourceContentTabPanel.class.getName() + ".";
private static final String OPERATION_SEARCH_TASKS_FOR_RESOURCE = DOT_CLASS + "seachTasks";
private static final String OPERATION_CHANGE_OWNER = DOT_CLASS + "changeOwner";
private static final String OPERATION_LOAD_SHADOW_OWNER = DOT_CLASS + "loadOwner";
private static final String OPERATION_UPDATE_STATUS = DOT_CLASS + "updateStatus";
private static final String OPERATION_DELETE_OBJECT = DOT_CLASS + "deleteObject";
private static final String OPERATION_IMPORT_OBJECT = DOT_CLASS + "importObject";
private static final String ID_TABLE = "table";
private static final String ID_LABEL = "label";
private static final String ID_IMPORT = "import";
private static final String ID_RECONCILIATION = "reconciliation";
private static final String ID_LIVE_SYNC = "liveSync";
private static final String ID_TOTALS = "totals";
private PageBase pageBase;
private ShadowKindType kind;
private String searchMode;
private String intent;
private QName objectClass;
private SelectableBeanObjectDataProvider<ShadowType> provider;
IModel<PrismObject<ResourceType>> resourceModel;
public ResourceContentPanel(String id, IModel<PrismObject<ResourceType>> resourceModel, QName objectClass,
ShadowKindType kind, String intent, String searchMode, PageBase pageBase) {
super(id);
this.pageBase = pageBase;
this.kind = kind;
this.searchMode = searchMode;
this.resourceModel = resourceModel;
this.intent = intent;
this.objectClass = objectClass;
initLayout();
}
public PageBase getPageBase() {
return pageBase;
}
public ShadowKindType getKind() {
return kind;
}
public String getIntent() {
return intent;
}
public IModel<PrismObject<ResourceType>> getResourceModel() {
return resourceModel;
}
public QName getObjectClass() {
return objectClass;
}
public RefinedObjectClassDefinition getDefinitionByKind() throws SchemaException {
RefinedResourceSchema refinedSchema = RefinedResourceSchemaImpl
.getRefinedSchema(resourceModel.getObject(), getPageBase().getPrismContext());
if (refinedSchema == null) {
warn("No schema found in resource. Please check your configuration and try to test connection for the resource.");
return null;
}
return refinedSchema.getRefinedDefinition(getKind(), getIntent());
}
public RefinedObjectClassDefinition getDefinitionByObjectClass() throws SchemaException {
RefinedResourceSchema refinedSchema = RefinedResourceSchemaImpl
.getRefinedSchema(resourceModel.getObject(), getPageBase().getPrismContext());
if (refinedSchema == null) {
warn("No schema found in resource. Please check your configuration and try to test connection for the resource.");
return null;
}
return refinedSchema.getRefinedDefinition(getObjectClass());
}
private TableId getTableId() {
if (kind == null) {
return TableId.PAGE_RESOURCE_OBJECT_CLASS_PANEL;
}
if (searchMode == null) {
searchMode = SessionStorage.KEY_RESOURCE_PAGE_REPOSITORY_CONTENT;
}
if (searchMode.equals(SessionStorage.KEY_RESOURCE_PAGE_REPOSITORY_CONTENT)) {
switch (kind) {
case ACCOUNT:
return TableId.PAGE_RESOURCE_ACCOUNTS_PANEL_REPOSITORY_MODE;
case GENERIC:
return TableId.PAGE_RESOURCE_GENERIC_PANEL_REPOSITORY_MODE;
case ENTITLEMENT:
return TableId.PAGE_RESOURCE_ENTITLEMENT_PANEL_REPOSITORY_MODE;
default:
return TableId.PAGE_RESOURCE_OBJECT_CLASS_PANEL;
}
} else if (searchMode.equals(SessionStorage.KEY_RESOURCE_PAGE_RESOURCE_CONTENT)){
switch (kind) {
case ACCOUNT:
return TableId.PAGE_RESOURCE_ACCOUNTS_PANEL_RESOURCE_MODE;
case GENERIC:
return TableId.PAGE_RESOURCE_GENERIC_PANEL_RESOURCE_MODE;
case ENTITLEMENT:
return TableId.PAGE_RESOURCE_ENTITLEMENT_PANEL_RESOURCE_MODE;
default:
return TableId.PAGE_RESOURCE_OBJECT_CLASS_PANEL;
}
}
return TableId.PAGE_RESOURCE_OBJECT_CLASS_PANEL;
}
private void initLayout() {
WebMarkupContainer totals = new WebMarkupContainer(ID_TOTALS);
totals.setOutputMarkupId(true);
add(totals);
initShadowStatistics(totals);
MainObjectListPanel<ShadowType> shadowListPanel = new MainObjectListPanel<ShadowType>(ID_TABLE,
ShadowType.class, getTableId(), null, pageBase) {
private static final long serialVersionUID = 1L;
@Override
protected List<InlineMenuItem> createInlineMenu() {
return ResourceContentPanel.this.createRowMenuItems();
}
@Override
protected List<IColumn<SelectableBean<ShadowType>, String>> createColumns() {
return ResourceContentPanel.this.initColumns();
}
@Override
protected IColumn<SelectableBean<ShadowType>, String> createActionsColumn(){
return new InlineMenuHeaderColumn(createHeaderMenuItems());
}
@Override
protected void objectDetailsPerformed(AjaxRequestTarget target, ShadowType object) {
shadowDetailsPerformed(target, WebComponentUtil.getName(object), object.getOid());
}
@Override
protected void newObjectPerformed(AjaxRequestTarget target) {
// TODO Auto-generated method stub
}
@Override
protected BaseSortableDataProvider<SelectableBean<ShadowType>> initProvider() {
provider = (SelectableBeanObjectDataProvider<ShadowType>) super.initProvider();
provider.setEmptyListOnNullQuery(true);
provider.setSort(null);
createSearchOptions(provider);
return provider;
}
@Override
protected ObjectQuery createContentQuery() {
ObjectQuery parentQuery = super.createContentQuery();
List<ObjectFilter> filters = new ArrayList<>();
if (parentQuery != null) {
filters.add(parentQuery.getFilter());
}
ObjectQuery customQuery = ResourceContentPanel.this.createQuery();
if (customQuery != null && customQuery.getFilter() != null) {
filters.add(customQuery.getFilter());
}
ObjectQuery query = new ObjectQuery();
if (filters.size() == 1) {
query = ObjectQuery.createObjectQuery(filters.iterator().next());
// setProviderAvailableDataSize(query);
return query;
}
if (filters.size() == 0) {
// setProviderAvailableDataSize(query);
return null;
}
query = ObjectQuery.createObjectQuery(AndFilter.createAnd(filters));
// setProviderAvailableDataSize(query);
return query;
}
@Override
protected Search createSearch() {
return ResourceContentPanel.this.createSearch();
}
};
shadowListPanel.setOutputMarkupId(true);
shadowListPanel.add(new VisibleEnableBehaviour() {
private static final long serialVersionUID = 1L;
@Override
public boolean isVisible() {
return createQuery() != null;
}
});
shadowListPanel.setAdditionalBoxCssClasses(GuiStyleConstants.CLASS_OBJECT_SHADOW_BOX_CSS_CLASSES);
add(shadowListPanel);
Label label = new Label(ID_LABEL, "Nothing to show. Select intent to search");
add(label);
label.setOutputMarkupId(true);
label.add(new VisibleEnableBehaviour() {
private static final long serialVersionUID = 1L;
@Override
public boolean isVisible() {
return createQuery() == null;
}
});
OperationResult result = new OperationResult(OPERATION_SEARCH_TASKS_FOR_RESOURCE);
List<PrismObject<TaskType>> tasks = WebModelServiceUtils
.searchObjects(TaskType.class,
QueryBuilder.queryFor(TaskType.class, getPageBase().getPrismContext())
.item(TaskType.F_OBJECT_REF).ref(getResourceModel().getObject().getOid())
.build(),
result, getPageBase());
List<TaskType> tasksForKind = getTasksForKind(tasks);
List<TaskType> importTasks = new ArrayList<>();
List<TaskType> syncTasks = new ArrayList<>();
List<TaskType> reconTasks = new ArrayList<>();
for (TaskType task : tasksForKind) {
if (TaskCategory.RECONCILIATION.equals(task.getCategory())) {
reconTasks.add(task);
} else if (TaskCategory.LIVE_SYNCHRONIZATION.equals(task.getCategory())) {
syncTasks.add(task);
} else if (TaskCategory.IMPORTING_ACCOUNTS.equals(task.getCategory())) {
importTasks.add(task);
}
}
initButton(ID_IMPORT, "Import", " fa-download", TaskCategory.IMPORTING_ACCOUNTS, importTasks);
initButton(ID_RECONCILIATION, "Reconciliation", " fa-link", TaskCategory.RECONCILIATION, reconTasks);
initButton(ID_LIVE_SYNC, "Live Sync", " fa-refresh", TaskCategory.LIVE_SYNCHRONIZATION, syncTasks);
initCustomLayout();
}
protected abstract void initShadowStatistics(WebMarkupContainer totals);
private void initButton(String id, String label, String icon, final String category,
final List<TaskType> tasks) {
List<InlineMenuItem> items = new ArrayList<>();
InlineMenuItem item = new InlineMenuItem(
getPageBase().createStringResource("ResourceContentResourcePanel.showExisting"),
new InlineMenuItemAction() {
private static final long serialVersionUID = 1L;
@Override
public void onClick(AjaxRequestTarget target) {
runTask(tasks, target);
}
});
items.add(item);
item = new InlineMenuItem(getPageBase().createStringResource("ResourceContentResourcePanel.newTask"),
new InlineMenuItemAction() {
private static final long serialVersionUID = 1L;
@Override
public void onClick(AjaxRequestTarget target) {
newTaskPerformed(category, target);
}
});
items.add(item);
DropdownButtonPanel button = new DropdownButtonPanel(id,
new DropdownButtonDto(String.valueOf(tasks.size()), icon, label, items));
add(button);
}
private void newTaskPerformed(String category, AjaxRequestTarget target) {
TaskType taskType = new TaskType();
PrismProperty<ShadowKindType> pKind;
try {
pKind = taskType.asPrismObject().findOrCreateProperty(
new ItemPath(TaskType.F_EXTENSION, SchemaConstants.MODEL_EXTENSION_KIND));
pKind.setRealValue(getKind());
} catch (SchemaException e) {
getSession().warn("Could not set kind for new task " + e.getMessage());
}
PrismProperty<String> pIntent;
try {
pIntent = taskType.asPrismObject().findOrCreateProperty(
new ItemPath(TaskType.F_EXTENSION, SchemaConstants.MODEL_EXTENSION_INTENT));
pIntent.setRealValue(getIntent());
} catch (SchemaException e) {
getSession().warn("Could not set kind for new task " + e.getMessage());
}
PrismObject<ResourceType> resource = getResourceModel().getObject();
taskType.setObjectRef(ObjectTypeUtil.createObjectRef(resource));
taskType.setCategory(category);
setResponsePage(new PageTaskAdd(taskType));
;
}
private void runTask(List<TaskType> tasks, AjaxRequestTarget target) {
ResourceTasksPanel tasksPanel = new ResourceTasksPanel(getPageBase().getMainPopupBodyId(), false,
new ListModel<TaskType>(tasks), getPageBase());
getPageBase().showMainPopup(tasksPanel, target);
}
private List<TaskType> getTasksForKind(List<PrismObject<TaskType>> tasks) {
List<TaskType> tasksForKind = new ArrayList<>();
for (PrismObject<TaskType> task : tasks) {
PrismProperty<ShadowKindType> taskKind = task
.findProperty(new ItemPath(TaskType.F_EXTENSION, SchemaConstants.MODEL_EXTENSION_KIND));
ShadowKindType taskKindValue = null;
if (taskKind != null) {
taskKindValue = taskKind.getRealValue();
PrismProperty<String> taskIntent = task.findProperty(
new ItemPath(TaskType.F_EXTENSION, SchemaConstants.MODEL_EXTENSION_INTENT));
String taskIntentValue = null;
if (taskIntent != null) {
taskIntentValue = taskIntent.getRealValue();
}
if (StringUtils.isNotEmpty(getIntent())) {
if (getKind() == taskKindValue && getIntent().equals(taskIntentValue)) {
tasksForKind.add(task.asObjectable());
}
} else if (getKind() == taskKindValue) {
tasksForKind.add(task.asObjectable());
}
}
}
return tasksForKind;
}
protected void initCustomLayout() {
// Nothing to do, for subclass extension
};
protected ObjectQuery createQuery() {
ObjectQuery baseQuery = null;
try {
if (kind == null) {
if (objectClass == null) {
return null;
}
return ObjectQueryUtil.createResourceAndObjectClassQuery(resourceModel.getObject().getOid(),
objectClass, getPageBase().getPrismContext());
}
RefinedObjectClassDefinition rOcDef = getDefinitionByKind();
if (rOcDef != null) {
if (rOcDef.getKind() != null) {
baseQuery = ObjectQueryUtil.createResourceAndKindIntent(
resourceModel.getObject().getOid(), rOcDef.getKind(), rOcDef.getIntent(),
getPageBase().getPrismContext());
} else {
baseQuery = ObjectQueryUtil.createResourceAndObjectClassQuery(
resourceModel.getObject().getOid(), rOcDef.getTypeName(),
getPageBase().getPrismContext());
}
}
} catch (SchemaException ex) {
LoggingUtils.logUnexpectedException(LOGGER,
"Could not crate query for shadows: " + ex.getMessage(), ex);
}
return baseQuery;
}
protected abstract Search createSearch();
private void createSearchOptions(SelectableBeanObjectDataProvider<ShadowType> provider) {
Collection<SelectorOptions<GetOperationOptions>> opts = SelectorOptions.createCollection(
ShadowType.F_ASSOCIATION, GetOperationOptions.createRetrieve(RetrieveOption.EXCLUDE));
if (addAdditionalOptions() != null) {
opts.add(addAdditionalOptions());
}
provider.setUseObjectCounting(isUseObjectCounting());
provider.setOptions(opts);
}
private StringResourceModel createStringResource(String key) {
return pageBase.createStringResource(key);
}
private List<IColumn<SelectableBean<ShadowType>, String>> initColumns() {
List<ColumnTypeDto<String>> columnDefs = Arrays.asList(
new ColumnTypeDto<String>("ShadowType.synchronizationSituation",
SelectableBean.F_VALUE + ".synchronizationSituation",
ShadowType.F_SYNCHRONIZATION_SITUATION.getLocalPart()),
new ColumnTypeDto<String>("ShadowType.intent", SelectableBean.F_VALUE + ".intent",
ShadowType.F_INTENT.getLocalPart()));
List<IColumn<SelectableBean<ShadowType>, String>> columns = new ArrayList<>();
IColumn<SelectableBean<ShadowType>, String> identifiersColumn = new AbstractColumn<SelectableBean<ShadowType>, String>(
createStringResource("pageContentAccounts.identifiers")) {
private static final long serialVersionUID = 1L;
@Override
public void populateItem(Item<ICellPopulator<SelectableBean<ShadowType>>> cellItem,
String componentId, IModel<SelectableBean<ShadowType>> rowModel) {
SelectableBean<ShadowType> dto = rowModel.getObject();
RepeatingView repeater = new RepeatingView(componentId);
ShadowType value = dto.getValue();
if (value != null) {
for (ResourceAttribute<?> attr : ShadowUtil.getAllIdentifiers(value)) {
repeater.add(new Label(repeater.newChildId(),
attr.getElementName().getLocalPart() + ": " + attr.getRealValue()));
}
}
cellItem.add(repeater);
}
};
columns.add(identifiersColumn);
columns.addAll((Collection) ColumnUtils.createColumns(columnDefs));
ObjectLinkColumn<SelectableBean<ShadowType>> ownerColumn = new ObjectLinkColumn<SelectableBean<ShadowType>>(
createStringResource("pageContentAccounts.owner")) {
private static final long serialVersionUID = 1L;
@Override
protected IModel<FocusType> createLinkModel(final IModel<SelectableBean<ShadowType>> rowModel) {
return new AbstractReadOnlyModel<FocusType>() {
private static final long serialVersionUID = 1L;
@Override
public FocusType getObject() {
FocusType owner = loadShadowOwner(rowModel);
if (owner == null) {
return null;
}
return owner;
}
};
}
@Override
public void onClick(AjaxRequestTarget target, IModel<SelectableBean<ShadowType>> rowModel,
ObjectType targetObjectType) {
ownerDetailsPerformed(target, (FocusType) targetObjectType);
}
};
columns.add(ownerColumn);
columns.add(new LinkColumn<SelectableBean<ShadowType>>(
createStringResource("PageAccounts.accounts.result")) {
private static final long serialVersionUID = 1L;
@Override
protected IModel<String> createLinkModel(final IModel<SelectableBean<ShadowType>> rowModel) {
return new AbstractReadOnlyModel<String>() {
private static final long serialVersionUID = 1L;
@Override
public String getObject() {
return getResultLabel(rowModel);
}
};
}
@Override
public void onClick(AjaxRequestTarget target, IModel<SelectableBean<ShadowType>> rowModel) {
OperationResultType resultType = getResult(rowModel);
OperationResult result = OperationResult.createOperationResult(resultType);
OperationResultPanel body = new OperationResultPanel(
ResourceContentPanel.this.getPageBase().getMainPopupBodyId(),
new Model<OpResult>(OpResult.getOpResult(pageBase, result)), getPage());
body.setOutputMarkupId(true);
ResourceContentPanel.this.getPageBase().showMainPopup(body, target);
}
});
return columns;
}
private OperationResultType getResult(IModel<SelectableBean<ShadowType>> model) {
ShadowType shadow = getShadow(model);
if (shadow == null) {
return null;
}
OperationResultType result = shadow.getResult();
if (result == null) {
return null;
}
return result;
}
private String getResultLabel(IModel<SelectableBean<ShadowType>> model) {
OperationResultType result = getResult(model);
if (result == null) {
return "";
}
StringBuilder b = new StringBuilder(
createStringResource("FailedOperationTypeType." + getShadow(model).getFailedOperationType())
.getObject());
b.append(":");
b.append(createStringResource("OperationResultStatusType." + result.getStatus()).getObject());
return b.toString();
}
private ShadowType getShadow(IModel<SelectableBean<ShadowType>> model) {
if (model == null || model.getObject() == null || model.getObject().getValue() == null) {
return null;
}
return (ShadowType) model.getObject().getValue();
}
private void ownerDetailsPerformed(AjaxRequestTarget target, FocusType owner) {
if (owner == null) {
return;
}
WebComponentUtil.dispatchToObjectDetailsPage(owner.getClass(), owner.getOid(), this, true);
}
private <F extends FocusType> F loadShadowOwner(IModel<SelectableBean<ShadowType>> model) {
ShadowType shadow = model.getObject().getValue();
String shadowOid;
if (shadow != null) {
shadowOid = shadow.getOid();
} else {
return null;
}
return loadShadowOwner(shadowOid);
}
private void shadowDetailsPerformed(AjaxRequestTarget target, String accountName, String accountOid) {
if (StringUtils.isEmpty(accountOid)) {
error(pageBase.getString("pageContentAccounts.message.cantShowAccountDetails", accountName,
accountOid));
target.add(pageBase.getFeedbackPanel());
return;
}
PageParameters parameters = new PageParameters();
parameters.add(OnePageParameterEncoder.PARAMETER, accountOid);
getPageBase().navigateToNext(PageAccount.class, parameters);
}
private <F extends FocusType> F loadShadowOwner(String shadowOid) {
Task task = pageBase.createSimpleTask(OPERATION_LOAD_SHADOW_OWNER);
OperationResult result = new OperationResult(OPERATION_LOAD_SHADOW_OWNER);
try {
PrismObject<? extends FocusType> prismOwner = pageBase.getModelService()
.searchShadowOwner(shadowOid, null, task, result);
if (prismOwner != null) {
return (F) prismOwner.asObjectable();
}
} catch (ObjectNotFoundException exception) {
// owner was not found, it's possible and it's ok on unlinked
// accounts
} catch (Exception ex) {
result.recordFatalError(pageBase.getString("PageAccounts.message.ownerNotFound", shadowOid), ex);
LoggingUtils.logUnexpectedException(LOGGER,
"Could not load owner of account with oid: " + shadowOid, ex);
} finally {
result.computeStatusIfUnknown();
}
if (WebComponentUtil.showResultInPage(result)) {
pageBase.showResult(result, false);
}
return null;
}
private List<InlineMenuItem> createHeaderMenuItems() {
List<InlineMenuItem> items = new ArrayList<InlineMenuItem>();
items.add(new InlineMenuItem(createStringResource("pageContentAccounts.menu.enableAccounts"), true,
new HeaderMenuAction(this) {
private static final long serialVersionUID = 1L;
@Override
public void onSubmit(AjaxRequestTarget target, Form<?> form) {
updateResourceObjectStatusPerformed(null, target, true);
}
}));
items.add(new InlineMenuItem(createStringResource("pageContentAccounts.menu.disableAccounts"), true,
new HeaderMenuAction(this) {
private static final long serialVersionUID = 1L;
@Override
public void onSubmit(AjaxRequestTarget target, Form<?> form) {
updateResourceObjectStatusPerformed(null, target, false);
}
}));
items.add(new InlineMenuItem(createStringResource("pageContentAccounts.menu.deleteAccounts"), true,
new HeaderMenuAction(this) {
private static final long serialVersionUID = 1L;
@Override
public void onSubmit(AjaxRequestTarget target, Form<?> form) {
deleteResourceObjectPerformed(null, target);
}
}));
items.add(new InlineMenuItem());
items.add(new InlineMenuItem(createStringResource("pageContentAccounts.menu.importAccounts"), true,
new HeaderMenuAction(this) {
private static final long serialVersionUID = 1L;
@Override
public void onSubmit(AjaxRequestTarget target, Form<?> form) {
importResourceObject(null, target);
}
}));
items.add(new InlineMenuItem());
items.add(new InlineMenuItem(createStringResource("pageContentAccounts.menu.removeOwners"), true,
new HeaderMenuAction(this) {
private static final long serialVersionUID = 1L;
@Override
public void onSubmit(AjaxRequestTarget target, Form<?> form) {
changeOwner(null, target, null, Operation.REMOVE);
}
}));
return items;
}
@SuppressWarnings("serial")
private List<InlineMenuItem> createRowMenuItems() {
List<InlineMenuItem> items = new ArrayList<InlineMenuItem>();
items.add(new InlineMenuItem(createStringResource("pageContentAccounts.menu.enableAccount"), true,
new ColumnMenuAction<SelectableBean<ShadowType>>() {
@Override
public void onSubmit(AjaxRequestTarget target, Form<?> form) {
SelectableBean<ShadowType> shadow = getRowModel().getObject();
updateResourceObjectStatusPerformed(shadow.getValue(), target, true);
}
}));
items.add(new InlineMenuItem(createStringResource("pageContentAccounts.menu.disableAccount"), true,
new ColumnMenuAction<SelectableBean<ShadowType>>() {
@Override
public void onSubmit(AjaxRequestTarget target, Form<?> form) {
SelectableBean<ShadowType> shadow = getRowModel().getObject();
updateResourceObjectStatusPerformed(shadow.getValue(), target, false);
}
}));
items.add(new InlineMenuItem(createStringResource("pageContentAccounts.menu.deleteAccount"), true,
new ColumnMenuAction<SelectableBean<ShadowType>>() {
@Override
public void onSubmit(AjaxRequestTarget target, Form<?> form) {
SelectableBean<ShadowType> shadow = getRowModel().getObject();
deleteResourceObjectPerformed(shadow.getValue(), target);
}
}));
items.add(new InlineMenuItem());
items.add(new InlineMenuItem(createStringResource("pageContentAccounts.menu.importAccount"), true,
new ColumnMenuAction<SelectableBean<ShadowType>>() {
@Override
public void onSubmit(AjaxRequestTarget target, Form<?> form) {
SelectableBean<ShadowType> shadow = getRowModel().getObject();
importResourceObject(shadow.getValue(), target);
}
}));
items.add(new InlineMenuItem());
items.add(new InlineMenuItem(createStringResource("pageContentAccounts.menu.removeOwner"), true,
new ColumnMenuAction<SelectableBean<ShadowType>>() {
@Override
public void onSubmit(AjaxRequestTarget target, Form<?> form) {
SelectableBean<ShadowType> shadow = getRowModel().getObject();
changeOwner(shadow.getValue(), target, null, Operation.REMOVE);
}
}));
items.add(new InlineMenuItem(createStringResource("pageContentAccounts.menu.changeOwner"), true,
new ColumnMenuAction<SelectableBean<ShadowType>>() {
@Override
public void onSubmit(AjaxRequestTarget target, Form<?> form) {
final SelectableBean<ShadowType> shadow = getRowModel().getObject();
ObjectBrowserPanel<FocusType> browser = new ObjectBrowserPanel<FocusType>(
pageBase.getMainPopupBodyId(), UserType.class,
WebComponentUtil.createFocusTypeList(), false, pageBase) {
@Override
protected void onSelectPerformed(AjaxRequestTarget target, FocusType focus) {
changeOwner(shadow.getValue(), target, focus, Operation.MODIFY);
}
};
pageBase.showMainPopup(browser, target);
}
}));
return items;
}
protected void importResourceObject(ShadowType selected, AjaxRequestTarget target) {
List<ShadowType> selectedShadow = null;
if (selected != null) {
selectedShadow = new ArrayList<>();
selectedShadow.add(selected);
} else {
selectedShadow = getTable().getSelectedObjects();
}
OperationResult result = new OperationResult(OPERATION_IMPORT_OBJECT);
Task task = pageBase.createSimpleTask(OPERATION_IMPORT_OBJECT);
if (selectedShadow == null || selectedShadow.isEmpty()) {
result.recordWarning("Nothing select to import");
getPageBase().showResult(result);
target.add(getPageBase().getFeedbackPanel());
return;
}
for (ShadowType shadow : selectedShadow) {
try {
getPageBase().getModelService().importFromResource(shadow.getOid(), task, result);
} catch (ObjectNotFoundException | SchemaException | SecurityViolationException
| CommunicationException | ConfigurationException e) {
result.recordPartialError("Could not import account " + shadow, e);
LOGGER.error("Could not import account {} ", shadow, e);
continue;
}
}
result.computeStatusIfUnknown();
getPageBase().showResult(result);
getTable().refreshTable(null, target);
target.add(getPageBase().getFeedbackPanel());
}
// TODO: as a task?
protected void deleteResourceObjectPerformed(ShadowType selected, AjaxRequestTarget target) {
final List<ShadowType> selectedShadow = getSelectedShadowsList(selected);
final OperationResult result = new OperationResult(OPERATION_DELETE_OBJECT);
if (selectedShadow == null || selectedShadow.isEmpty()) {
result.recordWarning("Nothing selected to delete");
getPageBase().showResult(result);
target.add(getPageBase().getFeedbackPanel());
return;
}
ConfirmationPanel dialog = new ConfirmationPanel(((PageBase) getPage()).getMainPopupBodyId(),
createDeleteConfirmString(selected, "pageContentAccounts.message.deleteConfirmation",
"pageContentAccounts.message.deleteConfirmationSingle")) {
@Override
public void yesPerformed(AjaxRequestTarget target) {
((PageBase) getPage()).hideMainPopup(target);
deleteAccountConfirmedPerformed(target, result, selectedShadow);
}
};
((PageBase) getPage()).showMainPopup(dialog, target);
}
private void deleteAccountConfirmedPerformed(AjaxRequestTarget target, OperationResult result,
List<ShadowType> selected) {
Task task = pageBase.createSimpleTask(OPERATION_DELETE_OBJECT);
ModelExecuteOptions opts = createModelOptions();
for (ShadowType shadow : selected) {
try {
ObjectDelta<ShadowType> deleteDelta = ObjectDelta.createDeleteDelta(ShadowType.class,
shadow.getOid(), getPageBase().getPrismContext());
getPageBase().getModelService().executeChanges(
WebComponentUtil.createDeltaCollection(deleteDelta), opts, task, result);
} catch (ObjectAlreadyExistsException | ObjectNotFoundException | SchemaException
| ExpressionEvaluationException | CommunicationException | ConfigurationException
| PolicyViolationException | SecurityViolationException e) {
result.recordPartialError("Could not delete object " + shadow, e);
LOGGER.error("Could not delete {}, using option {}", shadow, opts, e);
continue;
}
}
result.computeStatusIfUnknown();
getPageBase().showResult(result);
getTable().refreshTable(null, target);
target.add(getPageBase().getFeedbackPanel());
}
private IModel<String> createDeleteConfirmString(final ShadowType selected, final String oneDeleteKey,
final String moreDeleteKey) {
return new AbstractReadOnlyModel<String>() {
@Override
public String getObject() {
List<ShadowType> selectedShadow = getSelectedShadowsList(selected);
switch (selectedShadow.size()) {
case 1:
Object first = selectedShadow.get(0);
String name = WebComponentUtil.getName(((ShadowType) first));
return getPageBase().createStringResource(oneDeleteKey, name).getString();
default:
return getPageBase().createStringResource(moreDeleteKey, selectedShadow.size())
.getString();
}
}
};
}
protected abstract ModelExecuteOptions createModelOptions();
protected void updateResourceObjectStatusPerformed(ShadowType selected, AjaxRequestTarget target,
boolean enabled) {
List<ShadowType> selectedShadow = getSelectedShadowsList(selected);
OperationResult result = new OperationResult(OPERATION_UPDATE_STATUS);
Task task = pageBase.createSimpleTask(OPERATION_UPDATE_STATUS);
if (selectedShadow == null || selectedShadow.isEmpty()) {
result.recordWarning("Nothing selected to update status");
getPageBase().showResult(result);
target.add(getPageBase().getFeedbackPanel());
return;
}
ModelExecuteOptions opts = createModelOptions();
for (ShadowType shadow : selectedShadow) {
ActivationStatusType status = enabled ? ActivationStatusType.ENABLED
: ActivationStatusType.DISABLED;
try {
ObjectDelta<ShadowType> deleteDelta = ObjectDelta.createModificationReplaceProperty(
ShadowType.class, shadow.getOid(),
SchemaConstants.PATH_ACTIVATION_ADMINISTRATIVE_STATUS,
getPageBase().getPrismContext(), status);
getPageBase().getModelService().executeChanges(
WebComponentUtil.createDeltaCollection(deleteDelta), opts, task, result);
} catch (ObjectAlreadyExistsException | ObjectNotFoundException | SchemaException
| ExpressionEvaluationException | CommunicationException | ConfigurationException
| PolicyViolationException | SecurityViolationException e) {
// TODO Auto-generated catch block
result.recordPartialError("Could not update status (to " + status + ") for " + shadow, e);
LOGGER.error("Could not update status (to {}) for {}, using option {}", status, shadow, opts,
e);
continue;
}
}
result.computeStatusIfUnknown();
getPageBase().showResult(result);
getTable().refreshTable(null, target);
target.add(getPageBase().getFeedbackPanel());
}
private PrismObjectDefinition<FocusType> getFocusDefinition() {
return pageBase.getPrismContext().getSchemaRegistry()
.findObjectDefinitionByCompileTimeClass(FocusType.class);
}
private MainObjectListPanel<ShadowType> getTable() {
return (MainObjectListPanel<ShadowType>) get(pageBase.createComponentPath(ID_TABLE));
}
private void changeOwner(ShadowType selected, AjaxRequestTarget target, FocusType ownerToChange,
Operation operation) {
List<ShadowType> selectedShadow = getSelectedShadowsList(selected);
Collection<? extends ItemDelta> modifications = new ArrayList<>();
ReferenceDelta delta = null;
switch (operation) {
case REMOVE:
for (ShadowType shadow : selectedShadow) {
modifications = new ArrayList<>();
FocusType owner = loadShadowOwner(shadow.getOid());
if (owner != null) {
delta = ReferenceDelta.createModificationDelete(FocusType.F_LINK_REF,
getFocusDefinition(),
ObjectTypeUtil.createObjectRef(shadow).asReferenceValue());
((Collection) modifications).add(delta);
changeOwnerInternal(owner.getOid(), modifications, target);
}
}
break;
case MODIFY:
if (!isSatisfyConstraints(selectedShadow)) {
break;
}
ShadowType shadow = selectedShadow.iterator().next();
FocusType owner = loadShadowOwner(shadow.getOid());
if (owner != null) {
delta = ReferenceDelta.createModificationDelete(FocusType.F_LINK_REF,
getFocusDefinition(), ObjectTypeUtil.createObjectRef(shadow).asReferenceValue());
((Collection) modifications).add(delta);
changeOwnerInternal(owner.getOid(), modifications, target);
}
modifications = new ArrayList<>();
delta = ReferenceDelta.createModificationAdd(FocusType.F_LINK_REF, getFocusDefinition(),
ObjectTypeUtil.createObjectRef(shadow).asReferenceValue());
((Collection) modifications).add(delta);
changeOwnerInternal(ownerToChange.getOid(), modifications, target);
break;
}
}
private boolean isSatisfyConstraints(List selected) {
if (selected.size() > 1) {
error("Could not link to more than one owner");
return false;
}
if (selected.isEmpty()) {
warn("Could not link to more than one owner");
return false;
}
return true;
}
private void changeOwnerInternal(String ownerOid, Collection<? extends ItemDelta> modifications,
AjaxRequestTarget target) {
OperationResult result = new OperationResult(OPERATION_CHANGE_OWNER);
Task task = pageBase.createSimpleTask(OPERATION_CHANGE_OWNER);
ObjectDelta objectDelta = ObjectDelta.createModifyDelta(ownerOid, modifications, FocusType.class,
pageBase.getPrismContext());
Collection deltas = new ArrayList<>();
deltas.add(objectDelta);
try {
if (!deltas.isEmpty()) {
pageBase.getModelService().executeChanges(deltas, null, task, result);
}
} catch (ObjectAlreadyExistsException | ObjectNotFoundException | SchemaException
| ExpressionEvaluationException | CommunicationException | ConfigurationException
| PolicyViolationException | SecurityViolationException e) {
}
result.computeStatusIfUnknown();
pageBase.showResult(result);
target.add(pageBase.getFeedbackPanel());
getTable().refreshTable(null, target);
target.add(ResourceContentPanel.this);
}
private List<ShadowType> getSelectedShadowsList(ShadowType shadow) {
List<ShadowType> selectedShadow = null;
if (shadow != null) {
selectedShadow = new ArrayList<>();
selectedShadow.add(shadow);
} else {
provider.clearSelectedObjects();
selectedShadow = getTable().getSelectedObjects();
}
return selectedShadow;
}
protected abstract SelectorOptions<GetOperationOptions> addAdditionalOptions();
protected abstract boolean isUseObjectCounting();
}