com.r1soft.backup.server.web.GlobalUpdater.java Source code

Java tutorial

Introduction

Here is the source code for com.r1soft.backup.server.web.GlobalUpdater.java

Source

package com.r1soft.backup.server.web;

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.concurrent.ConcurrentHashMap;

import javax.imageio.ImageIO;

import org.apache.commons.lang.builder.EqualsBuilder;
import org.zkoss.zk.ui.Component;
import org.zkoss.zk.ui.Desktop;
import org.zkoss.zk.ui.WebApp;
import org.zkoss.zk.ui.event.Event;
import org.zkoss.zk.ui.event.EventQueue;
import org.zkoss.zk.ui.event.EventQueues;
import org.zkoss.zk.ui.util.DesktopCleanup;
import org.zkoss.zk.ui.util.DesktopInit;
import org.zkoss.zk.ui.util.WebAppCleanup;
import org.zkoss.zul.Image;
import org.zkoss.zul.Space;

import com.r1soft.backup.server.cache.CacheEntry;
import com.r1soft.backup.server.cache.SigarDiskCache;
import com.r1soft.backup.server.cache.SigarDiskCacheEntry;
import com.r1soft.backup.server.cache.VolumeCache;
import com.r1soft.backup.server.cache.VolumeCacheEntry;
import com.r1soft.backup.server.disksafe.metadata.DiskSafeManager;
import com.r1soft.backup.server.disksafe.metadata.MetaDataException;
import com.r1soft.backup.server.disksafe.metadata.entity.DiskSafeMetaData;
import com.r1soft.backup.server.disksafe.metadata.entity.RecoveryPoint;
import com.r1soft.backup.server.event.AgentEvent;
import com.r1soft.backup.server.event.ArchivePointActionEvent;
import com.r1soft.backup.server.event.ArchivePointEvent;
import com.r1soft.backup.server.event.DiskSafeCacheEvent;
import com.r1soft.backup.server.event.EventListener;
import com.r1soft.backup.server.event.GroupEvent;
import com.r1soft.backup.server.event.LicensingEvent;
import com.r1soft.backup.server.event.PolicyEvent;
import com.r1soft.backup.server.event.RecoveryPointEvent;
import com.r1soft.backup.server.event.StatsEvent;
import com.r1soft.backup.server.event.TaskHistoryEvent;
import com.r1soft.backup.server.event.UserEvent;
import com.r1soft.backup.server.event.VolumeCacheEvent;
import com.r1soft.backup.server.event.VolumeEvent;
import com.r1soft.backup.server.facade.CDPServerFacade;
import com.r1soft.backup.server.facade.LicenseFacade;
import com.r1soft.backup.server.facade.RecoveryPointInfo;
import com.r1soft.backup.server.facade.ServerProperties;
import com.r1soft.backup.server.facade.TaskFacade;
import com.r1soft.backup.server.facade.TaskSchedulerInfoSpec.TaskPoolType;
import com.r1soft.backup.server.i18n.I18NStrings;
import com.r1soft.backup.server.om.entity.EntityManagerFacade;
import com.r1soft.backup.server.om.entity.TaskState;
import com.r1soft.backup.server.om.pojo.DiskSafePointer;
import com.r1soft.backup.server.om.pojo.MergedRecoveryPointID;
import com.r1soft.backup.server.om.pojo.TaskExecutionContext;
import com.r1soft.backup.server.om.pojo.Volume;
import com.r1soft.backup.server.om.query.QueryComparisonOperator;
import com.r1soft.backup.server.om.query.QueryParameter;
import com.r1soft.backup.server.om.uuid.UUID;
import com.r1soft.backup.server.task.BaseDiskSafeTask;
import com.r1soft.backup.server.task.DataProtectionPolicyTask;
import com.r1soft.backup.server.task.MergeRecoveryPointsTask;
import com.r1soft.backup.server.web.agent.Controller.SelectableAgent;
import com.r1soft.backup.server.web.charts.ChartUtil;
import com.r1soft.backup.server.web.charts.DiskQuotaInfo;
import com.r1soft.backup.server.web.charts.IZkossImageChart;
import com.r1soft.backup.server.web.charts.TaskGauge;
import com.r1soft.backup.server.web.charts.TransferRateChart;
import com.r1soft.backup.server.web.component.RingChart;
import com.r1soft.backup.server.web.disksafe.Controller.SelectableDiskSafeCacheEntry;
import com.r1soft.backup.server.web.group.Controller.SelectableGroup;
import com.r1soft.backup.server.web.policy.Controller.SelectableDPPInfo;
import com.r1soft.backup.server.web.taskhistory.Controller.SelectableTaskExecutionContext;
import com.r1soft.backup.server.web.user.Controller.SelectableUser;
import com.r1soft.backup.server.web.volume.Controller.SelectableVolume;

public class GlobalUpdater implements DesktopInit, DesktopCleanup, WebAppCleanup {

    protected static final mazz.i18n.Logger logger = mazz.i18n.LoggerFactory.getLogger(GlobalUpdater.class);
    protected static final org.apache.log4j.Logger debug = org.apache.log4j.Logger.getLogger(GlobalUpdater.class);

    private static GlobalUpdaterThread updaterThread = null;
    private static Map<String, EventQueue> applicationEventQueues = null;
    private static List<Desktop> activeDesktops = new ArrayList<Desktop>();

    private static Map<String, DiskQuotaInfo> diskQuotaInfos = new ConcurrentHashMap<String, DiskQuotaInfo>();

    private static TransferRateChart networkBandwidthChart = null;
    private static Map<TaskPoolType, TaskGauge> taskGauges = new HashMap<TaskPoolType, TaskGauge>();
    private static final Map<String, RingChart> storageCharts = Collections
            .synchronizedMap(new HashMap<String, RingChart>());
    private static final Map<UUID, RingChart> volumeCharts = Collections
            .synchronizedMap(new HashMap<UUID, RingChart>());

    private static boolean shutdown = false;

    protected static final List<String> excludePaths = new ArrayList<String>();
    static {
        excludePaths.add("login.zul");
        ChartUtil.initLicense();
    }

    public GlobalUpdater() {
        // default constructor
    }

    protected static boolean isExcluded(Desktop desktop) {
        for (String exclude : excludePaths) {
            if (desktop.getRequestPath().contains(exclude))
                return true;
        }
        return false;
    }

    public static EventQueue lookupEventQueue(String eventQueue) {

        EventQueue queue = applicationEventQueues.get(eventQueue);
        if (queue != null)
            return queue;

        queue = EventQueues.lookup(eventQueue, EventQueues.APPLICATION, true);
        applicationEventQueues.put(eventQueue, queue);

        return queue;

    }

    public static void subscribeToEventQueue(String eventQueue, org.zkoss.zk.ui.event.EventListener eventListener) {
        lookupEventQueue(eventQueue).subscribe(eventListener);
    }

    public static void unsubscribeFromEventQueue(String eventQueue,
            org.zkoss.zk.ui.event.EventListener eventListener) {
        lookupEventQueue(eventQueue).unsubscribe(eventListener);
    }

    public static List<DiskQuotaInfo> getDiskQuotaInfos() {
        return new ArrayList<DiskQuotaInfo>(diskQuotaInfos.values());
    }

    /**
     *
     * @return will return null if chart is not ready
     */
    public static TransferRateChart getNetworkBandwidthChart() {
        return networkBandwidthChart;
    }

    public static Component getStorageChart(String mountPoint) {

        Component chart = null;

        if (storageCharts.containsKey(mountPoint)) {

            byte[] chartData = storageCharts.get(mountPoint).getContent().getByteData();

            try {
                ByteArrayInputStream bais = new ByteArrayInputStream(chartData);
                Image chartImg = new Image();
                chartImg.setContent(ImageIO.read(bais));
                chart = chartImg;
            } catch (IOException ex) {
                logger.error(ex, I18NStrings.ERROR_LOADING_CHART_CONTENT_FOR_MOUNT_POINT_X, mountPoint);
            }

        }

        if (chart == null) {
            Space space = new Space();
            space.setHeight("48");
            space.setWidth("48");
            chart = space;
        }

        return chart;
    }

    public static RingChart getVolumeChart(UUID volumeId) {
        return volumeCharts.get(volumeId);
    }

    /**
     *
     * @return will return null if chart is not ready
     */
    public static Map<TaskPoolType, TaskGauge> getTaskGauges() {
        return taskGauges;
    }

    private static synchronized void initEventQueues() {
        if (applicationEventQueues != null)
            return;

        applicationEventQueues = Collections.synchronizedMap(new HashMap<String, EventQueue>());
        applicationEventQueues.put(EventConstants.NATIVE_DISK_EVENT_QUEUE_NAME,
                EventQueues.lookup(EventConstants.NATIVE_DISK_EVENT_QUEUE_NAME, EventQueues.APPLICATION, true));
        applicationEventQueues.put(EventConstants.VOLUME_EVENT_QUEUE_NAME,
                EventQueues.lookup(EventConstants.VOLUME_EVENT_QUEUE_NAME, EventQueues.APPLICATION, true));
        applicationEventQueues.put(EventConstants.DISK_SAFE_EVENT_QUEUE_NAME,
                EventQueues.lookup(EventConstants.DISK_SAFE_EVENT_QUEUE_NAME, EventQueues.APPLICATION, true));
        applicationEventQueues.put(EventConstants.TASK_HISTORY_EVENT_QUEUE_NAME,
                EventQueues.lookup(EventConstants.TASK_HISTORY_EVENT_QUEUE_NAME, EventQueues.APPLICATION, true));
        applicationEventQueues.put(EventConstants.SERVER_INFO_EVENT_QUEUE_NAME,
                EventQueues.lookup(EventConstants.SERVER_INFO_EVENT_QUEUE_NAME, EventQueues.APPLICATION, true));
        applicationEventQueues.put(EventConstants.TASK_SCHEDULER_INFO_EVENT_QUEUE_NAME, EventQueues
                .lookup(EventConstants.TASK_SCHEDULER_INFO_EVENT_QUEUE_NAME, EventQueues.APPLICATION, true));
        applicationEventQueues.put(EventConstants.RECOVERY_POINT_EVENT_QUEUE_NAME,
                EventQueues.lookup(EventConstants.RECOVERY_POINT_EVENT_QUEUE_NAME, EventQueues.APPLICATION, true));
        applicationEventQueues.put(EventConstants.AGENT_EVENT_QUEUE_NAME,
                EventQueues.lookup(EventConstants.AGENT_EVENT_QUEUE_NAME, EventQueues.APPLICATION, true));
        applicationEventQueues.put(EventConstants.ARCHIVE_POINT_EVENT_QUEUE_NAME,
                EventQueues.lookup(EventConstants.ARCHIVE_POINT_EVENT_QUEUE_NAME, EventQueues.APPLICATION, true));
        applicationEventQueues.put(EventConstants.ARCHIVE_POINT_ACTION_EVENT_QUEUE_NAME, EventQueues
                .lookup(EventConstants.ARCHIVE_POINT_ACTION_EVENT_QUEUE_NAME, EventQueues.APPLICATION, true));
        applicationEventQueues.put(EventConstants.LICENSING_EVENT_QUEUE_NAME,
                EventQueues.lookup(EventConstants.LICENSING_EVENT_QUEUE_NAME, EventQueues.APPLICATION, true));
        applicationEventQueues.put(EventConstants.USER_EVENT_QUEUE_NAME,
                EventQueues.lookup(EventConstants.USER_EVENT_QUEUE_NAME, EventQueues.APPLICATION, true));
        applicationEventQueues.put(EventConstants.GROUP_EVENT_QUEUE_NAME,
                EventQueues.lookup(EventConstants.GROUP_EVENT_QUEUE_NAME, EventQueues.APPLICATION, true));
        applicationEventQueues.put(EventConstants.POLICY_EVENT_QUEUE_NAME,
                EventQueues.lookup(EventConstants.POLICY_EVENT_QUEUE_NAME, EventQueues.APPLICATION, true));
        applicationEventQueues.put(EventConstants.ZKOSS_IMAGE_CHART_EVENT_QUEUE_NAME, EventQueues
                .lookup(EventConstants.ZKOSS_IMAGE_CHART_EVENT_QUEUE_NAME, EventQueues.APPLICATION, true));
        applicationEventQueues.put(EventConstants.STATS_EVENT_QUEUE,
                EventQueues.lookup(EventConstants.STATS_EVENT_QUEUE, EventQueues.APPLICATION, true));

        // TODO: Simplify this shit by just using one EventConstants interface
        com.r1soft.backup.server.event.EventQueues
                .lookup(com.r1soft.backup.server.event.EventConstants.DISK_SAFE_EVENT_QUEUE, true)
                .subscribe(new EventListener() {
                    @Override
                    public void onEvent(com.r1soft.backup.server.event.Event event) {

                        if (shutdown)
                            return;
                        if (!(event instanceof DiskSafeCacheEvent))
                            return;

                        if (event.getName().equals(
                                com.r1soft.backup.server.event.EventConstants.DISK_SAFE_CACHE_ENTRY_UPDATE_EVENT)) {
                            applicationEventQueues.get(EventConstants.DISK_SAFE_EVENT_QUEUE_NAME)
                                    .publish(new Event(EventConstants.DISK_SAFE_UPDATE_EVENT_NAME, null,
                                            new SelectableDiskSafeCacheEntry(
                                                    ((DiskSafeCacheEvent) event).getDiskSafeCacheEntry())));
                        } else if (event.getName().equals(
                                com.r1soft.backup.server.event.EventConstants.DISK_SAFE_CACHE_ENTRY_REMOVE_EVENT)) {
                            applicationEventQueues.get(EventConstants.DISK_SAFE_EVENT_QUEUE_NAME)
                                    .publish(new Event(EventConstants.DISK_SAFE_DELETE_EVENT_NAME, null,
                                            new SelectableDiskSafeCacheEntry(
                                                    ((DiskSafeCacheEvent) event).getDiskSafeCacheEntry())));
                        }
                    }
                });

        com.r1soft.backup.server.event.EventQueues
                .lookup(com.r1soft.backup.server.event.EventConstants.VOLUME_EVENT_QUEUE, true)
                .subscribe(new EventListener() {
                    @Override
                    public void onEvent(com.r1soft.backup.server.event.Event event) {

                        if (shutdown)
                            return;
                        if (!(event instanceof VolumeEvent))
                            return;

                        if (event.getName()
                                .equals(com.r1soft.backup.server.event.EventConstants.VOLUME_CREATE_EVENT)) {
                            applicationEventQueues.get(EventConstants.VOLUME_EVENT_QUEUE_NAME)
                                    .publish(new Event(EventConstants.VOLUME_CREATE_EVENT_NAME, null,
                                            new SelectableVolume(((VolumeEvent) event).getVolume())));
                        } else if (event.getName()
                                .equals(com.r1soft.backup.server.event.EventConstants.VOLUME_UPDATE_EVENT)) {
                            applicationEventQueues.get(EventConstants.VOLUME_EVENT_QUEUE_NAME)
                                    .publish(new Event(EventConstants.VOLUME_UPDATE_EVENT_NAME, null,
                                            new SelectableVolume(((VolumeEvent) event).getVolume())));
                        } else if (event.getName()
                                .equals(com.r1soft.backup.server.event.EventConstants.VOLUME_DELETE_EVENT)) {
                            applicationEventQueues.get(EventConstants.VOLUME_EVENT_QUEUE_NAME)
                                    .publish(new Event(EventConstants.VOLUME_DELETE_EVENT_NAME, null,
                                            new SelectableVolume(((VolumeEvent) event).getVolume())));
                        } else if (event.getName()
                                .equals(com.r1soft.backup.server.event.EventConstants.VOLUME_REMOVE_EVENT)) {
                            applicationEventQueues.get(EventConstants.VOLUME_EVENT_QUEUE_NAME)
                                    .publish(new Event(EventConstants.VOLUME_DELETE_EVENT_NAME, null,
                                            new SelectableVolume(((VolumeEvent) event).getVolume())));
                        }
                    }
                });

        com.r1soft.backup.server.event.EventQueues
                .lookup(com.r1soft.backup.server.event.EventConstants.VOLUME_EVENT_QUEUE, true)
                .subscribe(new EventListener() {
                    @Override
                    public void onEvent(com.r1soft.backup.server.event.Event event) {

                        if (shutdown)
                            return;
                        if (!(event instanceof VolumeCacheEvent))
                            return;

                        if (event.getName().equals(
                                com.r1soft.backup.server.event.EventConstants.VOLUME_CACHE_ENTRY_UPDATE_EVENT)) {
                            applicationEventQueues.get(EventConstants.VOLUME_EVENT_QUEUE_NAME).publish(new Event(
                                    EventConstants.VOLUME_UPDATE_EVENT_NAME, null,
                                    new SelectableVolume(((VolumeCacheEvent) event).getVolumeCacheEntry())));
                        } else if (event.getName().equals(
                                com.r1soft.backup.server.event.EventConstants.VOLUME_CACHE_ENTRY_REMOVE_EVENT)) {
                            applicationEventQueues.get(EventConstants.VOLUME_EVENT_QUEUE_NAME).publish(new Event(
                                    EventConstants.VOLUME_DELETE_EVENT_NAME, null,
                                    new SelectableVolume(((VolumeCacheEvent) event).getVolumeCacheEntry())));
                        }
                    }
                });

        com.r1soft.backup.server.event.EventQueues
                .lookup(com.r1soft.backup.server.event.EventConstants.RECOVERY_POINT_EVENT_QUEUE, true)
                .subscribe(new EventListener() {
                    @Override
                    public void onEvent(com.r1soft.backup.server.event.Event event) {

                        if (shutdown)
                            return;
                        if (!(event instanceof RecoveryPointEvent))
                            return;

                        if (event.getName().equals(
                                com.r1soft.backup.server.event.EventConstants.RECOVERY_POINT_CREATE_EVENT)) {
                            applicationEventQueues.get(EventConstants.RECOVERY_POINT_EVENT_QUEUE_NAME)
                                    .publish(new Event(EventConstants.RECOVERY_POINT_CREATE_EVENT_NAME, null,
                                            ((RecoveryPointEvent) event).getRecoveryPointInfo()));
                        } else if (event.getName().equals(
                                com.r1soft.backup.server.event.EventConstants.RECOVERY_POINT_UPDATE_EVENT)) {
                            applicationEventQueues.get(EventConstants.RECOVERY_POINT_EVENT_QUEUE_NAME)
                                    .publish(new Event(EventConstants.RECOVERY_POINT_UPDATE_EVENT_NAME, null,
                                            ((RecoveryPointEvent) event).getRecoveryPointInfo()));
                        }
                    }
                });

        com.r1soft.backup.server.event.EventQueues
                .lookup(com.r1soft.backup.server.event.EventConstants.AGENT_EVENT_QUEUE, true)
                .subscribe(new EventListener() {
                    @Override
                    public void onEvent(com.r1soft.backup.server.event.Event event) {

                        if (shutdown)
                            return;
                        if (!(event instanceof AgentEvent))
                            return;

                        if (event.getName()
                                .equals(com.r1soft.backup.server.event.EventConstants.AGENT_CREATE_EVENT)) {
                            applicationEventQueues.get(EventConstants.AGENT_EVENT_QUEUE_NAME)
                                    .publish(new Event(EventConstants.AGENT_CREATE_EVENT_NAME, null,
                                            new SelectableAgent(((AgentEvent) event).getAgent())));
                        } else if (event.getName()
                                .equals(com.r1soft.backup.server.event.EventConstants.AGENT_UPDATE_EVENT)) {
                            applicationEventQueues.get(EventConstants.AGENT_EVENT_QUEUE_NAME)
                                    .publish(new Event(EventConstants.AGENT_UPDATE_EVENT_NAME, null,
                                            new SelectableAgent(((AgentEvent) event).getAgent())));
                        } else if (event.getName()
                                .equals(com.r1soft.backup.server.event.EventConstants.AGENT_DELETE_EVENT)) {
                            applicationEventQueues.get(EventConstants.AGENT_EVENT_QUEUE_NAME)
                                    .publish(new Event(EventConstants.AGENT_DELETE_EVENT_NAME, null,
                                            new SelectableAgent(((AgentEvent) event).getAgent())));
                        }
                    }
                });

        com.r1soft.backup.server.event.EventQueues
                .lookup(com.r1soft.backup.server.event.EventConstants.ARCHIVE_POINT_EVENT_QUEUE, true)
                .subscribe(new EventListener() {
                    @Override
                    public void onEvent(com.r1soft.backup.server.event.Event event) {

                        if (shutdown)
                            return;
                        if (!(event instanceof ArchivePointEvent))
                            return;

                        if (event.getName()
                                .equals(com.r1soft.backup.server.event.EventConstants.ARCHIVE_POINT_CREATE_EVENT)) {
                            applicationEventQueues.get(EventConstants.ARCHIVE_POINT_EVENT_QUEUE_NAME)
                                    .publish(new Event(EventConstants.ARCHIVE_POINT_CREATE_EVENT_NAME, null,
                                            ((ArchivePointEvent) event).getArchivePointInfo()));
                        } else if (event.getName()
                                .equals(com.r1soft.backup.server.event.EventConstants.ARCHIVE_POINT_UPDATE_EVENT)) {
                            applicationEventQueues.get(EventConstants.ARCHIVE_POINT_EVENT_QUEUE_NAME)
                                    .publish(new Event(EventConstants.ARCHIVE_POINT_UPDATE_EVENT_NAME, null,
                                            ((ArchivePointEvent) event).getArchivePointInfo()));
                        }
                    }
                });

        com.r1soft.backup.server.event.EventQueues
                .lookup(com.r1soft.backup.server.event.EventConstants.ARCHIVE_POINT_ACTION_EVENT_QUEUE, true)
                .subscribe(new EventListener() {
                    @Override
                    public void onEvent(com.r1soft.backup.server.event.Event event) {

                        if (shutdown)
                            return;
                        if (!(event instanceof ArchivePointActionEvent))
                            return;

                        if (event.getName().equals(
                                com.r1soft.backup.server.event.EventConstants.ARCHIVE_POINT_ACTION_CREATE_EVENT)) {
                            applicationEventQueues.get(EventConstants.ARCHIVE_POINT_ACTION_EVENT_QUEUE_NAME)
                                    .publish(new Event(EventConstants.ARCHIVE_POINT_ACTION_CREATE_EVENT_NAME, null,
                                            ((ArchivePointActionEvent) event).getArchivePointAction()));
                        }
                    }
                });

        com.r1soft.backup.server.event.EventQueues
                .lookup(com.r1soft.backup.server.event.EventConstants.LICENSING_EVENT_QUEUE, true)
                .subscribe(new EventListener() {
                    @Override
                    public void onEvent(com.r1soft.backup.server.event.Event event) {

                        if (shutdown)
                            return;
                        if (!(event instanceof LicensingEvent))
                            return;

                        if (event.getName().equals(
                                com.r1soft.backup.server.event.EventConstants.LICENSING_INFO_UPDATE_EVENT)) {
                            applicationEventQueues.get(EventConstants.LICENSING_EVENT_QUEUE_NAME)
                                    .publish(new Event(EventConstants.LICENSING_INFO_UPDATE_EVENT_NAME, null,
                                            ((LicensingEvent) event).getLicenseInfoSpec()));
                        }
                    }
                });

        com.r1soft.backup.server.event.EventQueues
                .lookup(com.r1soft.backup.server.event.EventConstants.TASK_HISTORY_EVENT_QUEUE, true)
                .subscribe(new EventListener() {
                    @Override
                    public void onEvent(com.r1soft.backup.server.event.Event event) {

                        if (shutdown)
                            return;
                        if (!(event instanceof TaskHistoryEvent))
                            return;

                        if (event.getName()
                                .equals(com.r1soft.backup.server.event.EventConstants.TASK_HISTORY_CREATE_EVENT)) {
                            applicationEventQueues.get(EventConstants.TASK_HISTORY_EVENT_QUEUE_NAME)
                                    .publish(new Event(EventConstants.TASK_HISTORY_CREATE_EVENT_NAME, null,
                                            new SelectableTaskExecutionContext(
                                                    ((TaskHistoryEvent) event).getTaskExecutionContext())));
                        } else if (event.getName()
                                .equals(com.r1soft.backup.server.event.EventConstants.TASK_HISTORY_UPDATE_EVENT)) {
                            applicationEventQueues.get(EventConstants.TASK_HISTORY_EVENT_QUEUE_NAME)
                                    .publish(new Event(EventConstants.TASK_HISTORY_UPDATE_EVENT_NAME, null,
                                            new SelectableTaskExecutionContext(
                                                    ((TaskHistoryEvent) event).getTaskExecutionContext())));
                        } else if (event.getName()
                                .equals(com.r1soft.backup.server.event.EventConstants.TASK_HISTORY_DELETE_EVENT)) {
                            applicationEventQueues.get(EventConstants.TASK_HISTORY_EVENT_QUEUE_NAME)
                                    .publish(new Event(EventConstants.TASK_HISTORY_DELETE_EVENT_NAME, null,
                                            new SelectableTaskExecutionContext(
                                                    ((TaskHistoryEvent) event).getTaskExecutionContext())));
                        }

                    }
                });

        com.r1soft.backup.server.event.EventQueues
                .lookup(com.r1soft.backup.server.event.EventConstants.USER_EVENT_QUEUE, true)
                .subscribe(new EventListener() {
                    @Override
                    public void onEvent(com.r1soft.backup.server.event.Event event) {

                        if (shutdown)
                            return;
                        if (!(event instanceof UserEvent))
                            return;

                        if (event.getName()
                                .equals(com.r1soft.backup.server.event.EventConstants.USER_CREATE_EVENT)) {
                            applicationEventQueues.get(EventConstants.USER_EVENT_QUEUE_NAME)
                                    .publish(new Event(EventConstants.USER_CREATE_EVENT_NAME, null,
                                            new SelectableUser(((UserEvent) event).getUser())));
                        } else if (event.getName()
                                .equals(com.r1soft.backup.server.event.EventConstants.USER_UPDATE_EVENT)) {
                            applicationEventQueues.get(EventConstants.USER_EVENT_QUEUE_NAME)
                                    .publish(new Event(EventConstants.USER_UPDATE_EVENT_NAME, null,
                                            new SelectableUser(((UserEvent) event).getUser())));
                        } else if (event.getName()
                                .equals(com.r1soft.backup.server.event.EventConstants.USER_DELETE_EVENT)) {
                            applicationEventQueues.get(EventConstants.USER_EVENT_QUEUE_NAME)
                                    .publish(new Event(EventConstants.USER_DELETE_EVENT_NAME, null,
                                            new SelectableUser(((UserEvent) event).getUser())));
                        }
                    }
                });

        com.r1soft.backup.server.event.EventQueues
                .lookup(com.r1soft.backup.server.event.EventConstants.GROUP_EVENT_QUEUE, true)
                .subscribe(new EventListener() {
                    @Override
                    public void onEvent(com.r1soft.backup.server.event.Event event) {

                        if (shutdown)
                            return;
                        if (!(event instanceof GroupEvent))
                            return;

                        if (event.getName()
                                .equals(com.r1soft.backup.server.event.EventConstants.GROUP_CREATE_EVENT)) {
                            applicationEventQueues.get(EventConstants.GROUP_EVENT_QUEUE_NAME)
                                    .publish(new Event(EventConstants.GROUP_CREATE_EVENT_NAME, null,
                                            new SelectableGroup(((GroupEvent) event).getGroup())));
                        } else if (event.getName()
                                .equals(com.r1soft.backup.server.event.EventConstants.GROUP_UPDATE_EVENT)) {
                            applicationEventQueues.get(EventConstants.GROUP_EVENT_QUEUE_NAME)
                                    .publish(new Event(EventConstants.GROUP_UPDATE_EVENT_NAME, null,
                                            new SelectableGroup(((GroupEvent) event).getGroup())));
                        } else if (event.getName()
                                .equals(com.r1soft.backup.server.event.EventConstants.GROUP_DELETE_EVENT)) {
                            applicationEventQueues.get(EventConstants.GROUP_EVENT_QUEUE_NAME)
                                    .publish(new Event(EventConstants.GROUP_DELETE_EVENT_NAME, null,
                                            new SelectableGroup(((GroupEvent) event).getGroup())));
                        }
                    }
                });

        com.r1soft.backup.server.event.EventQueues
                .lookup(com.r1soft.backup.server.event.EventConstants.POLICY_EVENT_QUEUE, true)
                .subscribe(new EventListener() {
                    @Override
                    public void onEvent(com.r1soft.backup.server.event.Event event) {

                        if (shutdown)
                            return;
                        if (!(event instanceof PolicyEvent))
                            return;

                        if (event.getName()
                                .equals(com.r1soft.backup.server.event.EventConstants.POLICY_CREATE_EVENT)) {
                            applicationEventQueues.get(EventConstants.POLICY_EVENT_QUEUE_NAME)
                                    .publish(new Event(EventConstants.POLICY_CREATE_EVENT_NAME, null,
                                            new SelectableDPPInfo(((PolicyEvent) event).getDPPInfo())));
                        } else if (event.getName()
                                .equals(com.r1soft.backup.server.event.EventConstants.POLICY_UPDATE_EVENT)) {
                            applicationEventQueues.get(EventConstants.POLICY_EVENT_QUEUE_NAME)
                                    .publish(new Event(EventConstants.POLICY_UPDATE_EVENT_NAME, null,
                                            new SelectableDPPInfo(((PolicyEvent) event).getDPPInfo())));
                        } else if (event.getName()
                                .equals(com.r1soft.backup.server.event.EventConstants.POLICY_DELETE_EVENT)) {
                            applicationEventQueues.get(EventConstants.POLICY_EVENT_QUEUE_NAME)
                                    .publish(new Event(EventConstants.POLICY_DELETE_EVENT_NAME, null,
                                            new SelectableDPPInfo(((PolicyEvent) event).getDPPInfo())));
                        }
                    }
                });

        com.r1soft.backup.server.event.EventQueues
                .lookup(com.r1soft.backup.server.event.EventConstants.STATS_EVENT_QUEUE, true)
                .subscribe(new EventListener() {

                    @Override
                    public void onEvent(com.r1soft.backup.server.event.Event event) {

                        if (shutdown || !(event instanceof StatsEvent))
                            return;

                        if (event.getName().equals(
                                com.r1soft.backup.server.event.EventConstants.RESTORE_STATS_UPDATED_EVENT)) {
                            lookupEventQueue(EventConstants.STATS_EVENT_QUEUE).publish(
                                    new Event(EventConstants.RESTORE_STATS_UPDATED_EVENT, null, event.getData()));
                        }

                    }

                });

    }

    private static synchronized void createThreadSingleton() {
        if (updaterThread != null)
            return;
        updaterThread = new GlobalUpdaterThread();
        updaterThread.start();
    }

    private static void stopThreadSingleton() {
        if (updaterThread == null)
            return;
        updaterThread.shutdownUpdater();
    }

    private static void start() {
        shutdown = false;
        initEventQueues();
        createThreadSingleton();
    }

    private static void shutdown() {
        shutdown = true;
        stopThreadSingleton();
        applicationEventQueues = null;
    }

    @Override
    public void init(Desktop desktop, Object req) throws Exception {

        GlobalUpdater.start();

        synchronized (activeDesktops) {
            if (!isExcluded(desktop)) {
                activeDesktops.add(desktop);
            }
        }
    }

    @Override
    public void cleanup(WebApp webapp) throws Exception {
        GlobalUpdater.shutdown();
    }

    @Override
    public void cleanup(Desktop desktop) throws Exception {
        synchronized (activeDesktops) {
            activeDesktops.remove(desktop);
        }
    }

    protected static class GlobalUpdaterThread extends Thread {

        protected static final long SLEEP_MILLIS = 5000L;
        protected static Long lastExecutionCheck = System.currentTimeMillis();

        protected static final QueryParameter<List<TaskState>> runningStatesParam;
        static {
            List<TaskState> runningStates = new ArrayList<TaskState>();
            runningStates.add(TaskState.QUEUED);
            runningStates.add(TaskState.RUNNING);
            runningStatesParam = new QueryParameter<List<TaskState>>("state", "state", runningStates,
                    QueryComparisonOperator.IN);
        }

        // FIXME this should just store a list of context IDs as storing the actial TECs can easily take 10 MB+
        protected List<TaskExecutionContext> runningContexts = null;

        protected boolean shutdown = false;

        public GlobalUpdaterThread() {
            // default constructor
        }

        public void shutdownUpdater() {
            synchronized (this) {
                if (!shutdown) {
                    shutdown = true;
                    this.notify();
                    networkBandwidthChart.shutdownUpdater();
                }
            }
        }

        @Override
        public void run() {
            this.setName(this.getClass().getSimpleName());

            long start = System.currentTimeMillis();

            // Keep looping
            for (;;) {
                List<String> activePaths = null;

                synchronized (this) {
                    if (shutdown)
                        break;
                }

                start = System.currentTimeMillis();

                synchronized (activeDesktops) {
                    if (!activeDesktops.isEmpty()) {
                        activePaths = new ArrayList<String>(activeDesktops.size());
                        for (Desktop desktop : activeDesktops) {
                            if (desktop.getRequestPath() != null)
                                activePaths.add(desktop.getRequestPath());
                        }
                    }
                }

                try {
                    if (activePaths != null)
                        doUpdates(activePaths);
                } catch (Throwable ex) {
                    logger.error(ex, I18NStrings.GLOBAL_UPDATER_FAILED_TO_UPDATE);
                }

                synchronized (this) {

                    if (shutdown)
                        break;

                    long sleep = SLEEP_MILLIS - (System.currentTimeMillis() - start);
                    try {
                        if (sleep > 0)
                            this.wait(sleep);
                    } catch (InterruptedException ex) {
                        // do nothing
                    }

                    if (shutdown)
                        break;

                }
            }
        }

        private void doUpdates(List<String> activePaths) {
            if (activePaths.isEmpty())
                return;

            boolean updateServerInfo = false, updateTaskSchedulerInfo = false, updateDiskQuotas = false,
                    updateVolumes = false, updateDiskSafes = false, updateTasks = false,
                    updateRecoveryPoints = false, updateLicenceInfo = false, updateCharts = false;

            for (String reqPath : activePaths) {

                // Someone's on the dashboard
                if (reqPath.equals("/") || reqPath.equals("/index.zul") || reqPath.contains("/Dashboard")) {
                    updateDiskQuotas = true;
                    updateTasks = true;
                    updateCharts = true;
                }
                // Someone's looking at agents
                else if (reqPath.contains("/Agent")) {
                    updateTasks = true;
                }
                // Someone's looking at control panel user list
                else if (reqPath.contains("/CP")) {
                    updateTasks = true;
                }
                // Someone's looking at disk safes
                else if (reqPath.contains("/DiskSafe")) {
                    updateDiskSafes = true;
                    updateTasks = true;
                }
                // Someone's looking at volumes
                else if (reqPath.contains("/Volume")) {
                    updateVolumes = true;
                }
                // Someone's looking at task history
                else if (reqPath.contains("/TaskHistory")) {
                    updateTasks = true;
                }
                // Someone's looking at configuration
                else if (reqPath.contains("/Configuration")) {
                    updateServerInfo = true;
                    updateTaskSchedulerInfo = true;
                    updateLicenceInfo = true;
                }
                // Someone's looking at Policies
                else if (reqPath.contains("/Policy")) {
                    updateTasks = true;
                }
                // Someone's looking at recovery points
                else if (reqPath.contains("/RecoveryPoints")) {
                    updateRecoveryPoints = true;
                }

                // Someone's looking at all screens we're updating, no point in checking more...
                if (updateServerInfo && updateDiskQuotas && updateVolumes && updateDiskSafes && updateTasks
                        && updateRecoveryPoints && updateLicenceInfo && updateCharts)
                    break;
            }

            /*
             * Don't let one failed update spoil all
             */
            try {
                if (updateServerInfo)
                    postServerInfoUpdates();
            } catch (Throwable ex) {
                logger.error(ex, I18NStrings.GLOBAL_UPDATER_FAILED_TO_UPDATE);
            }

            try {
                if (updateTaskSchedulerInfo)
                    postSchedulerInfoUpdates();
            } catch (Throwable ex) {
                logger.error(ex, I18NStrings.GLOBAL_UPDATER_FAILED_TO_UPDATE);
            }

            try {
                if (updateDiskQuotas)
                    postDiskQuotaUpdates();
            } catch (Throwable ex) {
                logger.error(ex, I18NStrings.GLOBAL_UPDATER_FAILED_TO_UPDATE);
            }

            try {
                if (updateTasks || updateRecoveryPoints)
                    postTaskUpdates();
            } catch (Throwable ex) {
                logger.error(ex, I18NStrings.GLOBAL_UPDATER_FAILED_TO_UPDATE);
            }

            try {
                if (updateLicenceInfo)
                    postLicenseInfoUpdates();
            } catch (Throwable ex) {
                logger.error(ex, I18NStrings.GLOBAL_UPDATER_FAILED_TO_UPDATE);
            }

            try {
                if (updateCharts)
                    updateCharts();
            } catch (Throwable ex) {
                logger.error(ex, I18NStrings.GLOBAL_UPDATER_FAILED_TO_UPDATE);
            }

        }

        private void postSchedulerInfoUpdates() {
            applicationEventQueues.get(EventConstants.TASK_SCHEDULER_INFO_EVENT_QUEUE_NAME)
                    .publish(new Event(EventConstants.TASK_SCHEDULER_INFO_UPDATE_EVENT_NAME, null,
                            CDPServerFacade.getTaskSchedulerInfoSpec()));
        }

        private void postServerInfoUpdates() {
            applicationEventQueues.get(EventConstants.SERVER_INFO_EVENT_QUEUE_NAME).publish(new Event(
                    EventConstants.SERVER_INFO_UPDATE_EVENT_NAME, null, CDPServerFacade.getServerInfoSpec()));
        }

        private void postLicenseInfoUpdates() {
            applicationEventQueues.get(EventConstants.LICENSING_EVENT_QUEUE_NAME).publish(new Event(
                    EventConstants.LICENSING_INFO_UPDATE_EVENT_NAME, null, LicenseFacade.getLicenseInfoSpec()));
        }

        private void postDiskQuotaUpdates() {
            ServerProperties serverProps;

            try {
                serverProps = CDPServerFacade.getServerProperties();
            } catch (IOException ex) {
                ex.printStackTrace();
                logger.error(ex, I18NStrings.GLOBAL_UPDATER_GET_SERVER_PROPERTIES_FAILED);
                return;
            }

            Integer hardQuota = serverProps.getHardQuota();
            Integer softQuota = serverProps.getSoftQuota();

            List<String> devicesOutOfScope = new ArrayList<String>(diskQuotaInfos.keySet());
            for (String storageDiskPath : CDPServerFacade.getStorageDiskPaths()) {

                SigarDiskCacheEntry cacheEntry = (SigarDiskCacheEntry) SigarDiskCache.getInstance()
                        .getCacheEntry(storageDiskPath);
                if (cacheEntry == null || cacheEntry.getDevice() == null)
                    continue;

                if (!diskQuotaInfos.containsKey(cacheEntry.getDevice().toLowerCase())) {
                    DiskQuotaInfo dqi = new DiskQuotaInfo(cacheEntry, softQuota, hardQuota);
                    dqi.initChart();
                    diskQuotaInfos.put(dqi.getDeviceName().toLowerCase(), dqi);
                } else {
                    DiskQuotaInfo dqi = diskQuotaInfos.get(cacheEntry.getDevice().toLowerCase());
                    devicesOutOfScope.remove(dqi.getDeviceName().toLowerCase());
                    // FIXME consider that update should return a boolean if anything changed and if it didn't we do not need to fire event
                    // or perhaps bytes of disk are likely always changing... so probably ok to update always
                    dqi.update(cacheEntry, softQuota, hardQuota);
                    dqi.updateChart();
                }
            }

            // FIXME we need to fire an update event for this
            for (String deviceOutOfScope : devicesOutOfScope) {
                diskQuotaInfos.remove(deviceOutOfScope);
            }

            List<DiskQuotaInfo> updates = new ArrayList<DiskQuotaInfo>(diskQuotaInfos.values());

            if (!updates.isEmpty()) {
                applicationEventQueues.get(EventConstants.NATIVE_DISK_EVENT_QUEUE_NAME)
                        .publish(new Event(EventConstants.NATIVE_DISKS_UPDATE_EVENT_NAME, null, updates));
            }
        }

        private void initRunningContexts() {
            if (runningContexts == null) {
                runningContexts = new ArrayList<TaskExecutionContext>();
                runningContexts.addAll(EntityManagerFacade.findPOJOByQueryParameter(TaskExecutionContext.class,
                        runningStatesParam));
            }
        }

        private void postTaskUpdates() {

            initRunningContexts();

            List<SelectableTaskExecutionContext> updates = new ArrayList<SelectableTaskExecutionContext>();
            List<SelectableTaskExecutionContext> created = new ArrayList<SelectableTaskExecutionContext>();

            List<TaskExecutionContext> remove = new ArrayList<TaskExecutionContext>();

            for (TaskExecutionContext ctx : runningContexts) {
                TaskExecutionContext updatedCTX = TaskFacade.getUpdatedTaskExecutionContext(ctx);
                if (updatedCTX != null) {
                    updates.add(new SelectableTaskExecutionContext(updatedCTX));
                    if (updatedCTX.getState() != TaskState.RUNNING && updatedCTX.getState() != TaskState.QUEUED)
                        remove.add(updatedCTX);
                } else {
                    remove.add(ctx);
                }
            }

            if (!remove.isEmpty())
                runningContexts.removeAll(remove);

            List<TaskExecutionContext> allRunning = EntityManagerFacade
                    .findPOJOByQueryParameter(TaskExecutionContext.class, runningStatesParam);

            for (TaskExecutionContext ctx : allRunning) {
                if (!runningContexts.contains(ctx)) {
                    runningContexts.add(ctx);
                    created.add(new SelectableTaskExecutionContext(ctx));
                }
            }

            Long currentExecutionCheck = System.currentTimeMillis();

            QueryParameter<Date> executionTimeParam = new QueryParameter<Date>("executionTime", "executionTime",
                    new Date(lastExecutionCheck), QueryComparisonOperator.GREATER_THAN_OR_EQUAL);

            lastExecutionCheck = currentExecutionCheck;

            List<TaskExecutionContext> recentlyCreated = EntityManagerFacade
                    .findPOJOByQueryParameter(TaskExecutionContext.class, executionTimeParam);

            for (TaskExecutionContext ctx : recentlyCreated) {
                if (!ctx.getState().equals(TaskState.QUEUED) && !ctx.getState().equals(TaskState.RUNNING)) {
                    if (!runningContexts.contains(ctx)) {
                        runningContexts.add(ctx);
                        created.add(new SelectableTaskExecutionContext(ctx));
                    }
                    updates.add(new SelectableTaskExecutionContext(ctx));
                }
            }

            List<SelectableTaskExecutionContext> all = new ArrayList<SelectableTaskExecutionContext>();

            if (!created.isEmpty()) {

                applicationEventQueues.get(EventConstants.TASK_HISTORY_EVENT_QUEUE_NAME)
                        .publish(new Event(EventConstants.TASKS_CREATE_EVENT_NAME, null, created));

                all.addAll(created);

            }

            if (!updates.isEmpty()) {

                applicationEventQueues.get(EventConstants.TASK_HISTORY_EVENT_QUEUE_NAME)
                        .publish(new Event(EventConstants.TASKS_UPDATE_EVENT_NAME, null, updates));

                all.addAll(updates);

            }

            if (!all.isEmpty())
                postRecoveryPointUpdates(all);

        }

        private void updateCharts() {
            //System.out.println("Start update charts: " + new Date());
            List<IZkossImageChart> updates = new ArrayList<IZkossImageChart>();

            /*
             * Update TransferRateChart
             */
            if (networkBandwidthChart == null) {
                networkBandwidthChart = new TransferRateChart();
                networkBandwidthChart.initChart();
            }

            /* generate test values   for chart
                RunningTaskStatsInfo runningTasksStatsInfo = new RunningTaskStatsInfo();
               long avgBytesSecond = ( ((long)(Calendar.getInstance().get(Calendar.SECOND))) * 100000L ) + ( ((long)(Calendar.getInstance().get(Calendar.MINUTE))) * 1000000L );
               runningTasksStatsInfo.setTotalBytesPerSecond(avgBytesSecond);
               runningTasksStatsInfo.setTotalReplicationBytesPerSecond((avgBytesSecond - ((long)(avgBytesSecond * 0.33))));
               runningTasksStatsInfo.setTotalRestoreBytesPerSecond((long)(avgBytesSecond * 0.33));
            //            runningTasksStatsInfo.setTotalBytesPerSecond(avgBytesSecond);
            //            runningTasksStatsInfo.setTotalReplicationBytesPerSecond(avgBytesSecond);
            //            runningTasksStatsInfo.setTotalRestoreBytesPerSecond(0L);
            */

            networkBandwidthChart.updateChart();
            updates.add(networkBandwidthChart);

            /*
             * Update Task Gauges
             */
            //         TaskSchedulerInfoSpec taskSchedulerInfoSpec = CDPServerFacade.getTaskSchedulerInfoSpec();
            //
            //         for( TaskPoolType poolType : TaskPoolType.values() ) {
            //            if( !taskGauges.containsKey(poolType) ) {
            //               TaskGauge taskGauge = new TaskGauge(poolType);
            //               taskGauge.initChart();
            //               taskGauges.put(poolType, taskGauge);
            //            }
            //
            //            TaskGauge taskGauge = taskGauges.get(poolType);
            //            taskGauge.updateChart(taskSchedulerInfoSpec.getTaskPoolSpec(poolType));
            //            updates.add(taskGauge);
            //         }

            try {

                ServerProperties serverProps = CDPServerFacade.getServerProperties();

                Integer hardQuota = serverProps.getHardQuota();
                Integer softQuota = serverProps.getSoftQuota();

                for (SigarDiskCacheEntry cacheEntry : SigarDiskCache.getInstance().getCacheEntries()) {

                    Double fullPercentage = cacheEntry.getFullPercentage();

                    RingChart existingChart = storageCharts.get(cacheEntry.getMountPoint());

                    if (existingChart == null) {
                        RingChart ringChart = new RingChart(fullPercentage, softQuota.doubleValue(),
                                hardQuota.doubleValue());
                        storageCharts.put(cacheEntry.getMountPoint(), ringChart);
                    } else {

                        EqualsBuilder eb = new EqualsBuilder()
                                .append(existingChart.getPercentFull(), fullPercentage)
                                .append(existingChart.getWarningLimit(), softQuota)
                                .append(existingChart.getErrorLimit(), hardQuota);

                        if (!eb.isEquals()) {
                            RingChart ringChart = new RingChart(fullPercentage, softQuota.doubleValue(),
                                    hardQuota.doubleValue());
                            storageCharts.put(cacheEntry.getMountPoint(), ringChart);
                        }

                    }

                }

            } catch (IOException e) {
                logger.error(e, I18NStrings.COULD_NOT_LOAD_SERVER_PROPERTIES);
            }

            for (Entry<Volume, CacheEntry<Volume>> entry : VolumeCache.getInstance().getCacheMap().entrySet()) {

                VolumeCacheEntry cacheEntry = (VolumeCacheEntry) entry.getValue();

                Double hardQuota = entry.getKey().getHardQuota();
                Double softQuota = entry.getKey().getSoftQuota();
                Long usageBytes = cacheEntry.getOnDiskSize();
                Double fullPercentage = hardQuota > 0 && usageBytes != null ? usageBytes.doubleValue() / hardQuota
                        : 0;

                RingChart existingChart = volumeCharts.get(entry.getKey().getId());

                if (existingChart == null) {
                    RingChart ringChart = new RingChart(fullPercentage, softQuota, hardQuota);
                    volumeCharts.put(entry.getKey().getId(), ringChart);
                } else {

                    EqualsBuilder eb = new EqualsBuilder().append(existingChart.getPercentFull(), fullPercentage)
                            .append(existingChart.getWarningLimit(), softQuota)
                            .append(existingChart.getErrorLimit(), hardQuota);

                    if (!eb.isEquals()) {
                        RingChart ringChart = new RingChart(fullPercentage, softQuota.doubleValue(),
                                hardQuota.doubleValue());
                        volumeCharts.put(entry.getKey().getId(), ringChart);
                    }

                }

            }

            applicationEventQueues.get(EventConstants.ZKOSS_IMAGE_CHART_EVENT_QUEUE_NAME)
                    .publish(new Event(EventConstants.ZKOSS_IMAGE_CHARTS_UPDATE_EVENT, null, updates));
            //System.out.println("Finish update charts: " + new Date());
        }

        private void postRecoveryPointUpdates(List<SelectableTaskExecutionContext> updates) {

            Map<UUID, List<MergedRecoveryPointID>> mergeMap = new HashMap<UUID, List<MergedRecoveryPointID>>();

            for (SelectableTaskExecutionContext ctx : updates) {
                if (ctx.getCompletionTime() != null && (ctx.getTaskClass().equals(DataProtectionPolicyTask.class)
                        || ctx.getTaskClass().equals(MergeRecoveryPointsTask.class))) {

                    List<MergedRecoveryPointID> mrpIDs = TaskFacade.getMergedRecoveryPointsPrimaryKeys(ctx.getId());
                    if (mrpIDs.isEmpty())
                        continue;

                    UUID pointerID = (UUID) ctx.getContextData(BaseDiskSafeTask.DISK_SAFE_ID_KEY);

                    if (!mergeMap.containsKey(pointerID))
                        mergeMap.put(pointerID, new ArrayList<MergedRecoveryPointID>());
                    mergeMap.get(pointerID).addAll(mrpIDs);
                }
            }

            if (!mergeMap.keySet().isEmpty()) {

                List<RecoveryPointInfo> rpUpdates = new ArrayList<RecoveryPointInfo>();

                for (Entry<UUID, List<MergedRecoveryPointID>> mergeEntry : mergeMap.entrySet()) {

                    DiskSafePointer pointer = EntityManagerFacade.findPOJO(DiskSafePointer.class,
                            mergeEntry.getKey());
                    if (pointer == null || !pointer.isOpen())
                        continue;

                    List<MergedRecoveryPointID> mrpIDs = mergeEntry.getValue();

                    DiskSafeMetaData dsmd = null;

                    try {

                        dsmd = DiskSafeManager.getInstance().openDiskSafe(pointer.getDiskSafeFile());

                        for (MergedRecoveryPointID mrpID : mrpIDs) {
                            RecoveryPoint rp = dsmd.getRecoveryPoint(mrpID.getRecoveryPointID());
                            rpUpdates.add(new RecoveryPointInfo(pointer.getId(), rp));
                        }

                    } catch (MetaDataException e) {
                        logger.error(I18NStrings.COULD_NOT_LOAD_DISK_SAFE, pointer.getDescription());
                        continue;
                    } finally {
                        if (dsmd != null)
                            DiskSafeManager.getInstance().returnDiskSafe(pointer.getDiskSafeFile(), dsmd);
                    }

                }

                if (!rpUpdates.isEmpty()) {
                    applicationEventQueues.get(EventConstants.RECOVERY_POINT_EVENT_QUEUE_NAME)
                            .publish(new Event(EventConstants.RECOVERY_POINTS_UPDATE_EVENT_NAME, null, rpUpdates));
                }

            }

        }

    }

}