/* * Copyright 2014 Red Hat, Inc. and/or its affiliates. * * 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 org.dashbuilder.displayer.client; import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; import javax.enterprise.context.Dependent; import javax.inject.Inject; import org.dashbuilder.common.client.error.ClientRuntimeError; import org.dashbuilder.dataset.filter.DataSetFilter; import org.dashbuilder.dataset.group.DataSetGroup; import org.uberfire.mvp.Command; /** * The coordinator class holds a list of Displayer instances and it makes sure that the data shared among * all of them is properly synced. This means every time a data display modification request comes from any * of the displayer components the rest are updated to reflect those changes. */ @Dependent public class DisplayerCoordinator { protected List<Displayer> displayerList = new ArrayList<Displayer>(); protected Set<DisplayerListener> listenerSet = new HashSet<DisplayerListener>(); protected Map<RendererLibrary,List<Displayer>> rendererMap = new HashMap<RendererLibrary,List<Displayer>>(); protected CoordinatorListener coordinatorListener = new CoordinatorListener(); protected Map<Displayer,List<Displayer>> notificationVetoMap = new HashMap<Displayer, List<Displayer>>(); protected RendererManager rendererManager; @Inject public DisplayerCoordinator(RendererManager rendererManager) { this.rendererManager = rendererManager; } public void addListener(DisplayerListener... listeners) { if (listeners != null) { for (DisplayerListener listener : listeners) { listenerSet.add(listener); } for (Displayer displayer : displayerList) { displayer.addListener(listeners); } } } public void addDisplayers(Collection<Displayer> displayers) { if (displayers != null) { for (Displayer displayer : displayers) { addDisplayer(displayer); } } } public void addDisplayers(Displayer... displayers) { if (displayers != null) { for (Displayer displayer : displayers) { addDisplayer(displayer); } } } public void addDisplayer(Displayer displayer) { if (displayer != null) { displayerList.add(displayer); displayer.addListener(coordinatorListener); for (DisplayerListener listener : listenerSet) { displayer.addListener(listener); } RendererLibrary renderer = rendererManager.getRendererForDisplayer(displayer.getDisplayerSettings()); List<Displayer> rendererGroup = rendererMap.get(renderer); if (rendererGroup == null) { rendererGroup = new ArrayList<Displayer>(); rendererMap.put(renderer, rendererGroup); } rendererGroup.add(displayer); } } public List<Displayer> getDisplayerList() { return displayerList; } public boolean removeDisplayer(Displayer displayer) { if (displayer == null) { return false; } RendererLibrary renderer = rendererManager.getRendererForDisplayer(displayer.getDisplayerSettings()); List<Displayer> rendererGroup = rendererMap.get(renderer); if (rendererGroup != null) rendererGroup.remove(displayer); return displayerList.remove(displayer); } public void drawAll() { drawAll(null, null); } public void redrawAll() { redrawAll(null, null); } public void drawAll(Command onSuccess, Command onFailure) { coordinatorListener.init(onSuccess, onFailure, displayerList.size(), true); for (RendererLibrary renderer : rendererMap.keySet()) { List<Displayer> rendererGroup = rendererMap.get(renderer); renderer.draw(rendererGroup); } } public void redrawAll(Command onSuccess, Command onFailure) { coordinatorListener.init(onSuccess, onFailure, displayerList.size(), false); for (RendererLibrary renderer : rendererMap.keySet()) { List<Displayer> rendererGroup = rendererMap.get(renderer); renderer.redraw(rendererGroup); } } public void closeAll() { for (Displayer displayer : displayerList) { displayer.close(); } } public void clear() { closeAll(); displayerList.clear(); listenerSet.clear(); rendererMap.clear(); notificationVetoMap.clear(); } public void addNotificationVeto(Displayer target, List<Displayer> vetoedDisplayers) { notificationVetoMap.put(target, vetoedDisplayers); } public void addNotificationVeto(List<Displayer> vetoedDisplayers) { for (Displayer target: vetoedDisplayers) { notificationVetoMap.put(target, vetoedDisplayers); } } public boolean isNotificationVetoed(Displayer from, Displayer to) { List<Displayer> vetoList = notificationVetoMap.get(to); return vetoList != null && vetoList.contains(from); } /** * Internal class that listens to events raised by any of the Displayer instances handled by this coordinator. */ private class CoordinatorListener implements DisplayerListener { int count = 0; int total = 0; Command onSuccess; Command onFailure; boolean draw; protected void init(Command onSuccess, Command onFailure, int total, boolean draw) { count = 0; this.onSuccess = onSuccess; this.onFailure = onFailure; this.draw = draw; this.total = total; } protected void count() { count++; if (count == total && onSuccess != null) { onSuccess.execute(); } } protected void error() { count++; if (count == total && onFailure != null) { onFailure.execute(); } } @Override public void onDataLookup(Displayer displayer) { for (Displayer other : displayerList) { if (other != displayer && !isNotificationVetoed(displayer, other)) { other.onDataLookup(displayer); } } } @Override public void onDraw(Displayer displayer) { if (draw) { count(); } for (Displayer other : displayerList) { if (other == displayer) continue; other.onDraw(displayer); } } @Override public void onRedraw(Displayer displayer) { if (!draw) { count(); } for (Displayer other : displayerList) { if (other != displayer && !isNotificationVetoed(displayer, other)) { other.onRedraw(displayer); } } } public void onClose(Displayer displayer) { for (Displayer other : displayerList) { if (other != displayer && !isNotificationVetoed(displayer, other)) { other.onClose(displayer); } } } @Override public void onFilterEnabled(Displayer displayer, DataSetGroup groupOp) { for (Displayer other : displayerList) { if (other != displayer && !isNotificationVetoed(displayer, other)) { other.onFilterEnabled(displayer, groupOp); } } } @Override public void onFilterEnabled(Displayer displayer, DataSetFilter filter) { for (Displayer other : displayerList) { if (other != displayer && !isNotificationVetoed(displayer, other)) { other.onFilterEnabled(displayer, filter); } } } @Override public void onFilterReset(Displayer displayer, List<DataSetGroup> groupOps) { for (Displayer other : displayerList) { if (other != displayer && !isNotificationVetoed(displayer, other)) { other.onFilterReset(displayer, groupOps); } } } @Override public void onFilterReset(Displayer displayer, DataSetFilter filter) { for (Displayer other : displayerList) { if (other != displayer && !isNotificationVetoed(displayer, other)) { other.onFilterReset(displayer, filter); } } } @Override public void onError(final Displayer displayer, ClientRuntimeError error) { error(); for (Displayer other : displayerList) { if (other != displayer && !isNotificationVetoed(displayer, other)) { other.onError(displayer, error); } } } } }