/* * Copyright (C) 2006-2016 DLR, Germany * * All rights reserved * * http://www.rcenvironment.de/ */ package de.rcenvironment.components.excel.gui.view; import java.io.Serializable; import java.util.ArrayList; import java.util.Deque; import java.util.Iterator; import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.Observable; import org.apache.commons.logging.LogFactory; import de.rcenvironment.components.excel.common.ChannelValue; import de.rcenvironment.components.excel.common.ExcelComponentConstants; import de.rcenvironment.components.excel.common.ExcelUtils; import de.rcenvironment.core.communication.common.ResolvableNodeId; import de.rcenvironment.core.notification.Notification; import de.rcenvironment.core.notification.NotificationService; import de.rcenvironment.core.notification.NotificationSubscriber; import de.rcenvironment.core.notification.SimpleNotificationService; import de.rcenvironment.core.utils.common.rpc.RemoteOperationException; import de.rcenvironment.core.utils.common.security.AllowRemoteAccess; /** * ModelProvider of channels. * * @author Markus Kunde */ public class ModelProvider extends Observable implements NotificationSubscriber { private static final long serialVersionUID = 611752605431248651L; private List<ChannelValue> channelValues = null; private boolean areNotificationsMissed = true; private Long lastMissedNotification = null; private Deque<Notification> queuedNotifications = new LinkedList<Notification>(); private boolean isSubscribed = false; /** * Constructor. * */ public ModelProvider() { channelValues = new ArrayList<ChannelValue>(); } /** * Subscribing model to notifications at all platforms. * * @param componentIdentifier identifier of specific component * @param publishPlatform identifier of publishing platform * @throws RemoteOperationException when subscribing to remote notifications fails */ public void subscribeToLocalToolRunPlatForm(final String componentIdentifier, final ResolvableNodeId publishPlatform) throws RemoteOperationException { if (!isSubscribed) { SimpleNotificationService sns = new SimpleNotificationService(); Map<String, Long> lastMissedNotifications; try { lastMissedNotifications = sns.subscribe(componentIdentifier + ExcelComponentConstants.NOTIFICATION_SUFFIX, this, publishPlatform); } catch (RemoteOperationException e) { LogFactory.getLog(getClass()).error("Failed to subscribe to Excel run platform: " + e.getMessage()); return; } for (String notifId : lastMissedNotifications.keySet()) { Long lastMissedNumber = lastMissedNotifications.get(notifId); if (lastMissedNumber == NotificationService.NO_MISSED) { setNotificationsMissed(false); setLastMissedNotification(lastMissedNumber); } else { setNotificationsMissed(true); setLastMissedNotification(lastMissedNumber); } for (List<Notification> notifications : sns.getNotifications(notifId, publishPlatform).values()) { Iterator<Notification> notificationIterator = notifications.iterator(); while (notificationIterator.hasNext()) { notify(notificationIterator.next()); } } } isSubscribed = true; } } /** * Returns all ChannelValues. * * @return list of ChannelValues */ public List<ChannelValue> getChannelValues() { return channelValues; } /** * Method to add channelvalues to model. * * @param channelVals list of channelvalues to add to model */ public void addNewChannelValues(final List<ChannelValue> channelVals) { channelValues.addAll(channelVals); setChanged(); notifyObservers(); // Not nice, but workbook-object will not released. ExcelUtils.destroyGarbage(); } /** * Method to add channelvalues to model. * * @param cval channelvalue to add to model */ public void addNewChannelValue(final ChannelValue cval) { channelValues.add(cval); setChanged(); notifyObservers(); // Not nice, but workbook-object will not released. ExcelUtils.destroyGarbage(); } // TODO code copied from DefaultNotificationSubscriber; rework to subclass (create a nested class if necessary) @Override @AllowRemoteAccess public void receiveBatchedNotifications(List<Notification> notifications) { // catch all RTEs here so only transport errors can reach the remote caller try { for (Notification notification : notifications) { notify(notification); } } catch (RuntimeException e) { // Note: acquiring the logger dynamically as it will be used very rarely LogFactory.getLog(getClass()).error("Error in notification handler", e); } } private void notify(Notification notification) { if (areNotificationsMissed && lastMissedNotification == NotificationService.NO_MISSED) { queuedNotifications.add(notification); } else if (areNotificationsMissed && notification.getHeader().getNumber() > lastMissedNotification) { queuedNotifications.add(notification); } else { final Object body = notification.getBody(); if (body instanceof ChannelValue) { ChannelValue val = (ChannelValue) notification.getBody(); channelValues.add(val); setChanged(); notifyObservers(); // Not nice, but workbook-object will not released. ExcelUtils.destroyGarbage(); } if (areNotificationsMissed && notification.getHeader().getNumber() == lastMissedNotification) { while (!queuedNotifications.isEmpty()) { notify(queuedNotifications.getFirst()); } areNotificationsMissed = false; } } } @Override public Class<? extends Serializable> getInterface() { return NotificationSubscriber.class; } public void setLastMissedNotification(Long number) { lastMissedNotification = number; } public void setNotificationsMissed(boolean missed) { areNotificationsMissed = missed; } }