blob: 193191cdbf3f6cadcc2d1ff7d95e8aef342cc592 [file] [log] [blame]
Simon Huntf679c4e2016-04-01 17:02:24 -07001/*
Brian O'Connor5ab426f2016-04-09 01:19:45 -07002 * Copyright 2016-present Open Networking Laboratory
Simon Huntf679c4e2016-04-01 17:02:24 -07003 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package org.onosproject.ui.impl.topo;
18
Thomas Vachuska4d66d0a2016-04-15 15:48:13 -070019import com.google.common.collect.ImmutableSet;
Simon Huntf679c4e2016-04-01 17:02:24 -070020import org.apache.felix.scr.annotations.Activate;
21import org.apache.felix.scr.annotations.Component;
22import org.apache.felix.scr.annotations.Deactivate;
Thomas Vachuska4d66d0a2016-04-15 15:48:13 -070023import org.apache.felix.scr.annotations.Reference;
24import org.apache.felix.scr.annotations.ReferenceCardinality;
Simon Huntf679c4e2016-04-01 17:02:24 -070025import org.apache.felix.scr.annotations.Service;
Simon Huntd0fa2842016-10-24 18:04:05 -070026import org.onosproject.net.config.NetworkConfigEvent;
27import org.onosproject.net.config.NetworkConfigListener;
28import org.onosproject.net.config.NetworkConfigRegistry;
29import org.onosproject.net.config.basics.BasicUiTopoLayoutConfig;
Simon Hunt4f4ffc32016-08-03 18:30:47 -070030import org.onosproject.net.region.RegionId;
Simon Huntf679c4e2016-04-01 17:02:24 -070031import org.onosproject.ui.UiTopoLayoutService;
Simon Hunt4f4ffc32016-08-03 18:30:47 -070032import org.onosproject.ui.model.topo.UiRegion;
Simon Huntf679c4e2016-04-01 17:02:24 -070033import org.onosproject.ui.model.topo.UiTopoLayout;
Thomas Vachuska4d66d0a2016-04-15 15:48:13 -070034import org.onosproject.ui.model.topo.UiTopoLayoutId;
Simon Huntf679c4e2016-04-01 17:02:24 -070035import org.slf4j.Logger;
36import org.slf4j.LoggerFactory;
37
Simon Huntb1ce2602016-07-23 14:04:31 -070038import java.util.Collections;
Simon Huntd0fa2842016-10-24 18:04:05 -070039import java.util.HashMap;
Simon Hunt4f4ffc32016-08-03 18:30:47 -070040import java.util.List;
Thomas Vachuska4d66d0a2016-04-15 15:48:13 -070041import java.util.Map;
Thomas Vachuska92b016b2016-05-20 11:37:57 -070042import java.util.Objects;
Thomas Vachuska4d66d0a2016-04-15 15:48:13 -070043import java.util.Set;
Thomas Vachuska92b016b2016-05-20 11:37:57 -070044import java.util.stream.Collectors;
45
46import static com.google.common.base.Preconditions.checkNotNull;
Thomas Vachuskaeb851cd2016-07-21 15:41:05 -070047import static org.onosproject.ui.model.topo.UiTopoLayoutId.DEFAULT_ID;
Simon Huntf679c4e2016-04-01 17:02:24 -070048
49/**
50 * Manages the user interface topology layouts.
51 * Note that these layouts are persisted and distributed across the cluster.
52 */
53@Component(immediate = true)
54@Service
55public class UiTopoLayoutManager implements UiTopoLayoutService {
56
Thomas Vachuska92b016b2016-05-20 11:37:57 -070057 private static final String ID_NULL = "Layout ID cannot be null";
58 private static final String LAYOUT_NULL = "Layout cannot be null";
59
Simon Huntd0fa2842016-10-24 18:04:05 -070060 private final Logger log = LoggerFactory.getLogger(getClass());
Thomas Vachuska4d66d0a2016-04-15 15:48:13 -070061
Simon Huntd0fa2842016-10-24 18:04:05 -070062 private final InternalConfigListener cfgListener = new InternalConfigListener();
63 private final Map<UiTopoLayoutId, UiTopoLayout> layoutMap = new HashMap<>();
64
65 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
66 protected NetworkConfigRegistry cfgService;
67
Thomas Vachuska4d66d0a2016-04-15 15:48:13 -070068
Simon Huntf679c4e2016-04-01 17:02:24 -070069 @Activate
70 public void activate() {
Thomas Vachuska4d66d0a2016-04-15 15:48:13 -070071
Thomas Vachuska92b016b2016-05-20 11:37:57 -070072 // Create and add the default layout, if needed.
Simon Huntd0fa2842016-10-24 18:04:05 -070073 layoutMap.computeIfAbsent(DEFAULT_ID, UiTopoLayout::new);
74
75 cfgService.addListener(cfgListener);
76 cfgListener.initAllConfigs();
Thomas Vachuska92b016b2016-05-20 11:37:57 -070077
Simon Huntf679c4e2016-04-01 17:02:24 -070078 log.info("Started");
79 }
80
81 @Deactivate
82 public void deactivate() {
Simon Huntd0fa2842016-10-24 18:04:05 -070083 cfgService.removeListener(cfgListener);
84
Simon Huntf679c4e2016-04-01 17:02:24 -070085 log.info("Stopped");
86 }
87
88
89 @Override
Thomas Vachuska92b016b2016-05-20 11:37:57 -070090 public UiTopoLayout getRootLayout() {
91 return getLayout(DEFAULT_ID);
92 }
93
94 @Override
Thomas Vachuska4d66d0a2016-04-15 15:48:13 -070095 public Set<UiTopoLayout> getLayouts() {
96 return ImmutableSet.copyOf(layoutMap.values());
Simon Huntf679c4e2016-04-01 17:02:24 -070097 }
98
99 @Override
100 public boolean addLayout(UiTopoLayout layout) {
Thomas Vachuska92b016b2016-05-20 11:37:57 -0700101 checkNotNull(layout, LAYOUT_NULL);
Simon Huntd0fa2842016-10-24 18:04:05 -0700102 return layoutMap.put(layout.id(), layout) == null;
Thomas Vachuska4d66d0a2016-04-15 15:48:13 -0700103 }
104
105 @Override
106 public UiTopoLayout getLayout(UiTopoLayoutId layoutId) {
Thomas Vachuska92b016b2016-05-20 11:37:57 -0700107 checkNotNull(layoutId, ID_NULL);
Thomas Vachuska4d66d0a2016-04-15 15:48:13 -0700108 return layoutMap.get(layoutId);
Simon Huntf679c4e2016-04-01 17:02:24 -0700109 }
110
111 @Override
Simon Hunt4f4ffc32016-08-03 18:30:47 -0700112 public UiTopoLayout getLayout(RegionId regionId) {
113 if (regionId == null || regionId.equals(UiRegion.NULL_ID)) {
114 return getRootLayout();
115 }
116
117 List<UiTopoLayout> matchingLayouts = layoutMap.values().stream()
118 .filter(l -> Objects.equals(regionId, l.regionId()))
119 .collect(Collectors.toList());
120 return matchingLayouts.isEmpty() ? null : matchingLayouts.get(0);
121 }
122
123 @Override
Simon Hunt98189192016-07-29 19:02:27 -0700124 public Set<UiTopoLayout> getPeerLayouts(UiTopoLayoutId layoutId) {
Simon Huntb1ce2602016-07-23 14:04:31 -0700125 checkNotNull(layoutId, ID_NULL);
Simon Hunt98189192016-07-29 19:02:27 -0700126
Simon Huntb1ce2602016-07-23 14:04:31 -0700127 UiTopoLayout layout = layoutMap.get(layoutId);
Simon Hunt98189192016-07-29 19:02:27 -0700128 if (layout == null || layout.isRoot()) {
Simon Huntb1ce2602016-07-23 14:04:31 -0700129 return Collections.emptySet();
130 }
131
132 UiTopoLayoutId parentId = layout.parent();
133 return layoutMap.values().stream()
Simon Hunte43cccebf2016-09-01 17:01:58 -0700134 // all layouts who are NOT me (or root) and who share my parent...
Simon Huntb1ce2602016-07-23 14:04:31 -0700135 .filter(l -> !Objects.equals(l.id(), layoutId) &&
Simon Hunte43cccebf2016-09-01 17:01:58 -0700136 !Objects.equals(l.id(), UiTopoLayoutId.DEFAULT_ID) &&
Simon Huntb1ce2602016-07-23 14:04:31 -0700137 Objects.equals(l.parent(), parentId))
138 .collect(Collectors.toSet());
139 }
140
141 @Override
Thomas Vachuska92b016b2016-05-20 11:37:57 -0700142 public Set<UiTopoLayout> getChildren(UiTopoLayoutId layoutId) {
143 checkNotNull(layoutId, ID_NULL);
144 return layoutMap.values().stream()
Simon Hunt98189192016-07-29 19:02:27 -0700145 .filter(l -> !l.isRoot() && Objects.equals(l.parent(), layoutId))
Thomas Vachuska92b016b2016-05-20 11:37:57 -0700146 .collect(Collectors.toSet());
147 }
148
149 @Override
Simon Huntf679c4e2016-04-01 17:02:24 -0700150 public boolean removeLayout(UiTopoLayout layout) {
Thomas Vachuska92b016b2016-05-20 11:37:57 -0700151 checkNotNull(layout, LAYOUT_NULL);
Simon Huntd0fa2842016-10-24 18:04:05 -0700152 return layoutMap.remove(layout.id()) != null;
Simon Huntf679c4e2016-04-01 17:02:24 -0700153 }
Thomas Vachuska4d66d0a2016-04-15 15:48:13 -0700154
Simon Huntd0fa2842016-10-24 18:04:05 -0700155 /*
156 * Listens for changes to layout configs, updating instances as necessary
157 */
158 private class InternalConfigListener implements NetworkConfigListener {
159
160 // look up the current config by layout ID and apply it
161 private void updateLayoutConfig(UiTopoLayoutId id) {
162 BasicUiTopoLayoutConfig cfg =
163 cfgService.getConfig(id, BasicUiTopoLayoutConfig.class);
164
165 log.info("Updating Layout via config... {}: {}", id, cfg);
166
167 UiTopoLayout layout = layoutMap.get(id);
168
169 // NOTE: if a value is null, then that null-ness should be set
170 // TODO: add setters on UiTopoLayout and implement...
171// layout
172// .region(cfg.region())
173// .parent(cfg.parent())
174// .geomap(cfg.geomap())
175// .sprites(cfg.sprites())
176// .scale(cfg.scale())
177// .offsetX(cfg.offsetX())
178// .offsetY(cfg.offsetY());
179 }
180
181 private void initAllConfigs() {
182 log.info("Initializing layout configurations...");
183 layoutMap.keySet().forEach(this::updateLayoutConfig);
184 }
185
186 @Override
187 public void event(NetworkConfigEvent event) {
188 UiTopoLayoutId id = (UiTopoLayoutId) event.subject();
189 updateLayoutConfig(id);
190 }
191
192 @Override
193 public boolean isRelevant(NetworkConfigEvent event) {
194 return (event.type() == NetworkConfigEvent.Type.CONFIG_ADDED ||
195 event.type() == NetworkConfigEvent.Type.CONFIG_UPDATED) &&
196 event.configClass().equals(BasicUiTopoLayoutConfig.class);
197 }
198 }
Simon Huntf679c4e2016-04-01 17:02:24 -0700199}