com.evolveum.midpoint.web.page.admin.server.currentState.TaskStatePanel.java Source code

Java tutorial

Introduction

Here is the source code for com.evolveum.midpoint.web.page.admin.server.currentState.TaskStatePanel.java

Source

/*
 * Copyright (c) 2010-2015 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.server.currentState;

import com.evolveum.midpoint.prism.xml.XmlTypeConverter;
import com.evolveum.midpoint.schema.result.OperationResult;
import com.evolveum.midpoint.task.api.TaskCategory;
import com.evolveum.midpoint.util.logging.Trace;
import com.evolveum.midpoint.util.logging.TraceManager;
import com.evolveum.midpoint.web.component.data.TablePanel;
import com.evolveum.midpoint.web.component.data.column.EnumPropertyColumn;
import com.evolveum.midpoint.web.component.progress.StatisticsDtoModel;
import com.evolveum.midpoint.web.component.progress.StatisticsPanel;
import com.evolveum.midpoint.web.component.util.ListDataProvider;
import com.evolveum.midpoint.web.component.util.SimplePanel;
import com.evolveum.midpoint.web.component.util.VisibleEnableBehaviour;
import com.evolveum.midpoint.web.page.PageBase;
import com.evolveum.midpoint.web.page.admin.server.PageTaskEdit;
import com.evolveum.midpoint.web.page.admin.server.dto.TaskDto;
import com.evolveum.midpoint.web.page.admin.server.dto.TaskDtoExecutionStatus;
import com.evolveum.midpoint.xml.ns._public.common.common_3.IterativeTaskInformationType;
import com.evolveum.midpoint.xml.ns._public.common.common_3.OperationStatsType;
import org.apache.commons.lang.time.DurationFormatUtils;
import org.apache.wicket.extensions.markup.html.repeater.data.table.IColumn;
import org.apache.wicket.extensions.markup.html.repeater.data.table.ISortableDataProvider;
import org.apache.wicket.extensions.markup.html.repeater.data.table.PropertyColumn;
import org.apache.wicket.extensions.markup.html.repeater.util.SortableDataProvider;
import org.apache.wicket.markup.html.basic.Label;
import org.apache.wicket.model.AbstractReadOnlyModel;
import org.apache.wicket.model.IModel;
import org.apache.wicket.model.PropertyModel;
import org.apache.wicket.model.ResourceModel;

import javax.xml.datatype.XMLGregorianCalendar;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Date;
import java.util.List;

import static com.evolveum.midpoint.web.page.PageTemplate.createStringResourceStatic;

/**
 * @author mederly
 */
public class TaskStatePanel extends SimplePanel<TaskCurrentStateDto> {

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

    private static final String ID_UPDATED = "updated";
    private static final String ID_COUNTERS_SOURCE = "countersSource";

    private static final String ID_EXECUTION_STATUS = "executionStatus";
    private static final String ID_EXECUTION_NODE = "executionNode";
    private static final String ID_EXECUTION_TIME = "executionTime";

    private static final String ID_PROGRESS = "progress";

    private static final String ID_OBJECTS_PROCESSED_SUCCESS = "objectsProcessedSuccess";
    private static final String ID_OBJECTS_PROCESSED_SUCCESS_TIME = "objectsProcessedSuccessTime";
    private static final String ID_LAST_OBJECT_PROCESSED_SUCCESS = "lastObjectProcessedSuccess";
    private static final String ID_LAST_OBJECT_PROCESSED_SUCCESS_TIME = "lastObjectProcessedSuccessTime";
    private static final String ID_OBJECTS_PROCESSED_FAILURE = "objectsProcessedFailure";
    private static final String ID_OBJECTS_PROCESSED_FAILURE_TIME = "objectsProcessedFailureTime";
    private static final String ID_LAST_OBJECT_PROCESSED_FAILURE = "lastObjectProcessedFailure";
    private static final String ID_LAST_OBJECT_PROCESSED_FAILURE_TIME = "lastObjectProcessedFailureTime";
    private static final String ID_LAST_ERROR = "lastError";
    private static final String ID_CURRENT_OBJECT_PROCESSED = "currentObjectProcessed";
    private static final String ID_CURRENT_OBJECT_PROCESSED_TIME = "currentObjectProcessedTime";
    private static final String ID_OBJECTS_TOTAL = "objectsTotal";

    private static final String ID_SYNCHRONIZATION_INFORMATION_PANEL = "synchronizationInformationPanel";
    private static final String ID_ACTIONS_EXECUTED_INFORMATION_PANEL = "actionsExecutedInformationPanel";
    private static final String ID_STATISTICS_PANEL = "statisticsPanel";

    private static final String ID_WORKER_THREADS_TABLE = "workerThreadsTable";
    private static final String ID_WORKER_THREADS_TABLE_LABEL = "workerThreadsTableLabel";

    private static final String ID_OPERATION_RESULT = "operationResult";

    // ugly hack - TODO replace with something serious
    // we cannot work with handler uri, because it exists only as long as the task executes
    private static final Collection<String> WALL_CLOCK_AVG_CATEGORIES = Arrays.asList(TaskCategory.BULK_ACTIONS,
            TaskCategory.IMPORTING_ACCOUNTS, TaskCategory.RECOMPUTATION, TaskCategory.RECONCILIATION,
            TaskCategory.UTIL // this is a megahack: only utility tasks that count objects are DeleteTask and ShadowIntegrityCheck
    );

    private StatisticsDtoModel statisticsDtoModel;

    public TaskStatePanel(String id, IModel<TaskCurrentStateDto> model, final PageBase pageBase) {
        super(id, model);
    }

    @Override
    protected void initLayout() {

        Label updated = new Label(ID_UPDATED, new AbstractReadOnlyModel<String>() {
            @Override
            public String getObject() {
                return formatDate(new Date());
            }
        });
        add(updated);

        Label executionStatus = new Label(ID_EXECUTION_STATUS, new AbstractReadOnlyModel<String>() {
            @Override
            public String getObject() {
                TaskDtoExecutionStatus executionStatus = getModel().getObject().getTaskDto().getExecution();
                return getString(TaskDtoExecutionStatus.class.getSimpleName() + "." + executionStatus.name());
            }
        });
        add(executionStatus);

        Label executionNode = new Label(ID_EXECUTION_NODE, new AbstractReadOnlyModel<String>() {
            @Override
            public String getObject() {
                TaskDto dto = getModel().getObject().getTaskDto();
                if (!TaskDtoExecutionStatus.RUNNING.equals(dto.getExecution())) {
                    return null;
                }
                return getString("TaskStatePanel.message.node", dto.getExecutingAt());
            }
        });
        add(executionNode);

        Label executionTime = new Label(ID_EXECUTION_TIME, new AbstractReadOnlyModel<String>() {
            @Override
            public String getObject() {
                TaskDto dto = getModel().getObject().getTaskDto();
                if (dto == null) {
                    return null;
                }
                Long started = dto.getLastRunStartTimestampLong();
                Long finished = dto.getLastRunFinishTimestampLong();
                if (started == null) {
                    return null;
                }
                if (TaskDtoExecutionStatus.RUNNING.equals(dto.getExecution()) || finished == null
                        || finished < started) {
                    return getString("TaskStatePanel.message.executionTime.notFinished",
                            formatDate(new Date(started)),
                            DurationFormatUtils.formatDurationHMS(System.currentTimeMillis() - started));
                } else {
                    return getString("TaskStatePanel.message.executionTime.finished", formatDate(new Date(started)),
                            formatDate(new Date(finished)),
                            DurationFormatUtils.formatDurationHMS(finished - started));
                }
            }
        });
        add(executionTime);

        Label progress = new Label(ID_PROGRESS, new AbstractReadOnlyModel<String>() {
            @Override
            public String getObject() {
                TaskCurrentStateDto dto = getModelObject();
                TaskDto taskDto = dto.getTaskDto();
                if (taskDto == null) {
                    return null;
                } else {
                    return taskDto.getProgressDescription(dto.getCurrentProgress()); // TODO implement stalled since
                }
            }
        });
        add(progress);

        Label processedSuccess = new Label(ID_OBJECTS_PROCESSED_SUCCESS, new AbstractReadOnlyModel<String>() {
            @Override
            public String getObject() {
                TaskCurrentStateDto dto = getModelObject();
                if (dto == null) {
                    return null;
                }
                IterativeTaskInformationType info = dto.getIterativeTaskInformationType();
                if (info == null) {
                    return null;
                }
                if (info.getTotalSuccessCount() == 0) {
                    return "0";
                } else {
                    return getString("TaskStatePanel.message.objectsProcessed", info.getTotalSuccessCount());
                }
            }
        });
        add(processedSuccess);

        Label processedSuccessTime = new Label(ID_OBJECTS_PROCESSED_SUCCESS_TIME,
                new AbstractReadOnlyModel<String>() {
                    @Override
                    public String getObject() {
                        TaskCurrentStateDto dto = getModelObject();
                        if (dto == null) {
                            return null;
                        }
                        IterativeTaskInformationType info = dto.getIterativeTaskInformationType();
                        if (info == null) {
                            return null;
                        }
                        if (info.getTotalSuccessCount() == 0) {
                            return null;
                        } else {
                            return getString("TaskStatePanel.message.objectsProcessedTime",
                                    info.getTotalSuccessDuration() / 1000,
                                    info.getTotalSuccessDuration() / info.getTotalSuccessCount());
                        }
                    }
                });
        add(processedSuccessTime);

        Label lastProcessedSuccess = new Label(ID_LAST_OBJECT_PROCESSED_SUCCESS,
                new AbstractReadOnlyModel<String>() {
                    @Override
                    public String getObject() {
                        TaskCurrentStateDto dto = getModelObject();
                        if (dto == null) {
                            return null;
                        }
                        IterativeTaskInformationType info = dto.getIterativeTaskInformationType();
                        if (info == null) {
                            return null;
                        }
                        if (info.getLastSuccessObjectDisplayName() == null) {
                            return null;
                        } else {
                            return getString("TaskStatePanel.message.lastObjectProcessed",
                                    info.getLastSuccessObjectDisplayName());
                        }
                    }
                });
        add(lastProcessedSuccess);

        Label lastProcessedSuccessTime = new Label(ID_LAST_OBJECT_PROCESSED_SUCCESS_TIME,
                new AbstractReadOnlyModel<String>() {
                    @Override
                    public String getObject() {
                        TaskCurrentStateDto dto = getModelObject();
                        if (dto == null) {
                            return null;
                        }
                        IterativeTaskInformationType info = dto.getIterativeTaskInformationType();
                        if (info == null) {
                            return null;
                        }
                        if (info.getLastSuccessEndTimestamp() == null) {
                            return null;
                        } else {
                            if (showAgo(dto)) {
                                return getString("TaskStatePanel.message.timeInfoWithDurationAndAgo",
                                        formatDate(info.getLastSuccessEndTimestamp()),
                                        DurationFormatUtils.formatDurationWords(System.currentTimeMillis()
                                                - XmlTypeConverter.toMillis(info.getLastSuccessEndTimestamp()),
                                                true, true),
                                        info.getLastSuccessDuration());
                            } else {
                                return getString("TaskStatePanel.message.timeInfoWithDuration",
                                        formatDate(info.getLastSuccessEndTimestamp()),
                                        info.getLastSuccessDuration());
                            }
                        }
                    }
                });
        add(lastProcessedSuccessTime);

        Label processedFailure = new Label(ID_OBJECTS_PROCESSED_FAILURE, new AbstractReadOnlyModel<String>() {
            @Override
            public String getObject() {
                TaskCurrentStateDto dto = getModelObject();
                if (dto == null) {
                    return null;
                }
                IterativeTaskInformationType info = dto.getIterativeTaskInformationType();
                if (info == null) {
                    return null;
                }
                if (info.getTotalFailureCount() == 0) {
                    return "0";
                } else {
                    return getString("TaskStatePanel.message.objectsProcessed", info.getTotalFailureCount());
                }
            }
        });
        add(processedFailure);

        Label processedFailureTime = new Label(ID_OBJECTS_PROCESSED_FAILURE_TIME,
                new AbstractReadOnlyModel<String>() {
                    @Override
                    public String getObject() {
                        TaskCurrentStateDto dto = getModelObject();
                        if (dto == null) {
                            return null;
                        }
                        IterativeTaskInformationType info = dto.getIterativeTaskInformationType();
                        if (info == null) {
                            return null;
                        }
                        if (info.getTotalFailureCount() == 0) {
                            return null;
                        } else {
                            return getString("TaskStatePanel.message.objectsProcessedTime",
                                    info.getTotalFailureDuration() / 1000,
                                    info.getTotalFailureDuration() / info.getTotalFailureCount());
                        }
                    }
                });
        add(processedFailureTime);

        Label lastProcessedFailure = new Label(ID_LAST_OBJECT_PROCESSED_FAILURE,
                new AbstractReadOnlyModel<String>() {
                    @Override
                    public String getObject() {
                        TaskCurrentStateDto dto = getModelObject();
                        if (dto == null) {
                            return null;
                        }
                        IterativeTaskInformationType info = dto.getIterativeTaskInformationType();
                        if (info == null) {
                            return null;
                        }
                        if (info.getLastFailureObjectDisplayName() == null) {
                            return null;
                        } else {
                            return getString("TaskStatePanel.message.lastObjectProcessed",
                                    info.getLastFailureObjectDisplayName());
                        }
                    }
                });
        add(lastProcessedFailure);

        Label lastProcessedFailureTime = new Label(ID_LAST_OBJECT_PROCESSED_FAILURE_TIME,
                new AbstractReadOnlyModel<String>() {
                    @Override
                    public String getObject() {
                        TaskCurrentStateDto dto = getModelObject();
                        if (dto == null) {
                            return null;
                        }
                        IterativeTaskInformationType info = dto.getIterativeTaskInformationType();
                        if (info == null) {
                            return null;
                        }
                        if (info.getLastFailureEndTimestamp() == null) {
                            return null;
                        } else {
                            if (showAgo(dto)) {
                                return getString("TaskStatePanel.message.timeInfoWithDurationAndAgo",
                                        formatDate(info.getLastFailureEndTimestamp()),
                                        DurationFormatUtils.formatDurationWords(System.currentTimeMillis()
                                                - XmlTypeConverter.toMillis(info.getLastFailureEndTimestamp()),
                                                true, true),
                                        info.getLastFailureDuration());
                            } else {
                                return getString("TaskStatePanel.message.timeInfoWithDuration",
                                        formatDate(info.getLastFailureEndTimestamp()),
                                        info.getLastFailureDuration());
                            }
                        }
                    }
                });
        add(lastProcessedFailureTime);

        Label lastError = new Label(ID_LAST_ERROR, new AbstractReadOnlyModel<String>() {
            @Override
            public String getObject() {
                TaskCurrentStateDto dto = getModelObject();
                if (dto == null) {
                    return null;
                }
                IterativeTaskInformationType info = dto.getIterativeTaskInformationType();
                if (info == null) {
                    return null;
                }
                return info.getLastFailureExceptionMessage();
            }
        });
        add(lastError);

        Label currentObjectProcessed = new Label(ID_CURRENT_OBJECT_PROCESSED, new AbstractReadOnlyModel<String>() {
            @Override
            public String getObject() {
                TaskCurrentStateDto dto = getModelObject();
                if (dto == null) {
                    return null;
                }
                IterativeTaskInformationType info = dto.getIterativeTaskInformationType();
                if (info == null) {
                    return null;
                }
                return info.getCurrentObjectDisplayName();
            }
        });
        add(currentObjectProcessed);

        Label currentObjectProcessedTime = new Label(ID_CURRENT_OBJECT_PROCESSED_TIME,
                new AbstractReadOnlyModel<String>() {
                    @Override
                    public String getObject() {
                        TaskCurrentStateDto dto = getModelObject();
                        if (dto == null) {
                            return null;
                        }
                        IterativeTaskInformationType info = dto.getIterativeTaskInformationType();
                        if (info == null) {
                            return null;
                        }
                        if (info.getCurrentObjectStartTimestamp() == null) {
                            return null;
                        } else {
                            return getString("TaskStatePanel.message.timeInfoWithAgo",
                                    formatDate(info.getCurrentObjectStartTimestamp()),
                                    DurationFormatUtils.formatDurationWords(System.currentTimeMillis()
                                            - XmlTypeConverter.toMillis(info.getCurrentObjectStartTimestamp()),
                                            true, true));
                        }
                    }
                });
        add(currentObjectProcessedTime);

        Label objectsTotal = new Label(ID_OBJECTS_TOTAL, new AbstractReadOnlyModel<String>() {
            @Override
            public String getObject() {
                TaskCurrentStateDto dto = getModelObject();
                if (dto == null) {
                    return null;
                }
                IterativeTaskInformationType info = dto.getIterativeTaskInformationType();
                if (info == null) {
                    return null;
                }
                int objectsTotal = info.getTotalSuccessCount() + info.getTotalFailureCount();
                if (WALL_CLOCK_AVG_CATEGORIES.contains(dto.getTaskDto().getCategory())) {
                    Long avg = getWallClockAverage(dto, objectsTotal);
                    if (avg != null) {
                        return getString("TaskStatePanel.message.objectsTotal", objectsTotal, avg);
                    }
                }
                return String.valueOf(objectsTotal);
            }
        });
        add(objectsTotal);

        SynchronizationInformationPanel synchronizationInformationPanel = new SynchronizationInformationPanel(
                ID_SYNCHRONIZATION_INFORMATION_PANEL, new AbstractReadOnlyModel<SynchronizationInformationDto>() {
                    @Override
                    public SynchronizationInformationDto getObject() {
                        TaskCurrentStateDto dto = getModelObject();
                        if (dto == null) {
                            return null;
                        }
                        if (dto.getSynchronizationInformationType() == null) {
                            return null;
                        }
                        return new SynchronizationInformationDto(dto.getSynchronizationInformationType());
                    }
                });
        synchronizationInformationPanel.add(new VisibleEnableBehaviour() {
            @Override
            public boolean isVisible() {
                TaskCurrentStateDto dto = getModelObject();
                return dto != null && dto.getSynchronizationInformationType() != null;
            }
        });
        add(synchronizationInformationPanel);

        ActionsExecutedInformationPanel actionsExecutedInformationPanel = new ActionsExecutedInformationPanel(
                ID_ACTIONS_EXECUTED_INFORMATION_PANEL, new AbstractReadOnlyModel<ActionsExecutedInformationDto>() {
                    @Override
                    public ActionsExecutedInformationDto getObject() {
                        TaskCurrentStateDto dto = getModelObject();
                        if (dto == null) {
                            return null;
                        }
                        if (dto.getActionsExecutedInformationType() == null) {
                            return null;
                        }
                        return new ActionsExecutedInformationDto(dto.getActionsExecutedInformationType());
                    }
                });
        actionsExecutedInformationPanel.add(new VisibleEnableBehaviour() {
            @Override
            public boolean isVisible() {
                TaskCurrentStateDto dto = getModelObject();
                return dto != null && dto.getActionsExecutedInformationType() != null;
            }
        });
        add(actionsExecutedInformationPanel);

        Label countersSource = new Label(ID_COUNTERS_SOURCE, new AbstractReadOnlyModel<String>() {
            @Override
            public String getObject() {
                TaskCurrentStateDto dto = getModelObject();
                if (dto == null) {
                    return null;
                }
                OperationStatsType stats = dto.getOperationStatsType();
                if (stats == null) {
                    return null;
                }
                if (stats.isLiveInformation()) {
                    return getString("TaskStatePanel.message.countersSourceMemory",
                            formatDate(stats.getTimestamp()));
                } else {
                    return getString("TaskStatePanel.message.countersSourceRepository",
                            formatDate(stats.getTimestamp()));
                }
            }
        });
        add(countersSource);

        statisticsDtoModel = new StatisticsDtoModel(new AbstractReadOnlyModel<TaskDto>() {
            @Override
            public TaskDto getObject() {
                return getModelObject().getTaskDto();
            }
        });
        StatisticsPanel statisticsPanel = new StatisticsPanel(ID_STATISTICS_PANEL, statisticsDtoModel);
        add(statisticsPanel);

        VisibleEnableBehaviour hiddenWhenNoSubtasks = new VisibleEnableBehaviour() {
            @Override
            public boolean isVisible() {
                TaskDto taskDto = getModelObject().getTaskDto();
                return taskDto != null && !taskDto.getTransientSubtasks().isEmpty();
            }
        };

        Label workerThreadsTableLabel = new Label(ID_WORKER_THREADS_TABLE_LABEL,
                new ResourceModel("TaskStatePanel.workerThreads"));
        workerThreadsTableLabel.add(hiddenWhenNoSubtasks);
        add(workerThreadsTableLabel);
        List<IColumn<WorkerThreadDto, String>> columns = new ArrayList<>();
        columns.add(new PropertyColumn(createStringResourceStatic(this, "TaskStatePanel.subtaskName"),
                WorkerThreadDto.F_NAME));
        columns.add(new EnumPropertyColumn<WorkerThreadDto>(
                createStringResourceStatic(this, "TaskStatePanel.subtaskState"),
                WorkerThreadDto.F_EXECUTION_STATUS));
        columns.add(new PropertyColumn(createStringResourceStatic(this, "TaskStatePanel.subtaskObjectsProcessed"),
                WorkerThreadDto.F_PROGRESS));
        ISortableDataProvider<WorkerThreadDto, String> threadsProvider = new ListDataProvider<>(this,
                new AbstractReadOnlyModel<List<WorkerThreadDto>>() {
                    @Override
                    public List<WorkerThreadDto> getObject() {
                        List<WorkerThreadDto> rv = new ArrayList<>();
                        TaskDto taskDto = getModelObject().getTaskDto();
                        if (taskDto != null) {
                            for (TaskDto subtaskDto : taskDto.getTransientSubtasks()) {
                                rv.add(new WorkerThreadDto(subtaskDto));
                            }
                        }
                        return rv;
                    }
                });
        TablePanel<WorkerThreadDto> workerThreadsTablePanel = new TablePanel<>(ID_WORKER_THREADS_TABLE,
                threadsProvider, columns);
        workerThreadsTablePanel.add(hiddenWhenNoSubtasks);
        add(workerThreadsTablePanel);

        SortableDataProvider<OperationResult, String> provider = new ListDataProvider<>(this,
                new PropertyModel<List<OperationResult>>(getModel(), "taskDto.opResult"));
        TablePanel result = new TablePanel<>(ID_OPERATION_RESULT, provider, initResultColumns());
        result.setStyle("padding-top: 0px;");
        result.setShowPaging(false);
        result.setOutputMarkupId(true);
        add(result);
    }

    private String formatDate(XMLGregorianCalendar date) {
        return formatDate(XmlTypeConverter.toDate(date));
    }

    private String formatDate(Date date) {
        if (date == null) {
            return null;
        }
        return date.toLocaleString();
    }

    protected boolean showAgo(TaskCurrentStateDto dto) {
        boolean showAgo = false;
        TaskDto taskDto = dto.getTaskDto();
        if (taskDto != null) {
            Long started = taskDto.getLastRunStartTimestampLong();
            Long finished = taskDto.getLastRunFinishTimestampLong();
            if (started != null && (finished == null || finished < started)) {
                showAgo = true; // for all running tasks
            }
        }
        return showAgo;
    }

    private Long getWallClockAverage(TaskCurrentStateDto dto, int objectsTotal) {
        if (objectsTotal == 0) {
            return null;
        }
        if (dto == null || dto.getTaskDto() == null) {
            return null;
        }
        Long started = dto.getTaskDto().getLastRunStartTimestampLong();
        if (started == null) {
            return null;
        }
        Long finished = dto.getTaskDto().getLastRunFinishTimestampLong();
        if (finished == null || finished < started) {
            finished = System.currentTimeMillis();
        }
        return (finished - started) / objectsTotal;
    }

    private List<IColumn<OperationResult, String>> initResultColumns() {
        List<IColumn<OperationResult, String>> columns = new ArrayList<IColumn<OperationResult, String>>();

        columns.add(new PropertyColumn(createStringResource("pageTaskEdit.opResult.token"), "token"));
        columns.add(new PropertyColumn(createStringResource("pageTaskEdit.opResult.operation"), "operation"));
        columns.add(new PropertyColumn(createStringResource("pageTaskEdit.opResult.status"), "status"));
        columns.add(new PropertyColumn(createStringResource("pageTaskEdit.opResult.message"), "message"));
        return columns;
    }

    public void refreshModel(PageTaskEdit page) {
        IModel<TaskCurrentStateDto> model = getModel();
        if (!(model instanceof TaskCurrentStateDtoModel)) {
            LOGGER.warn("Unexpected or null model for TaskCurrentStateDto object: {}", model);
            return;
        }
        ((TaskCurrentStateDtoModel) model).refresh(page);
        if (statisticsDtoModel != null) {
            statisticsDtoModel.invalidateCache();
        }
    }
}