blob: 7441672eb5b185ec859f2b35552feb46e15236af [file] [log] [blame]
Simon Huntf679c4e2016-04-01 17:02:24 -07001/*
Brian O'Connora09fe5b2017-08-03 21:12:30 -07002 * Copyright 2016-present Open Networking Foundation
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 Huntd0fa2842016-10-24 18:04:05 -070020import org.onosproject.net.config.NetworkConfigEvent;
21import org.onosproject.net.config.NetworkConfigListener;
22import org.onosproject.net.config.NetworkConfigRegistry;
23import org.onosproject.net.config.basics.BasicUiTopoLayoutConfig;
Simon Hunt4f4ffc32016-08-03 18:30:47 -070024import org.onosproject.net.region.RegionId;
Simon Huntf679c4e2016-04-01 17:02:24 -070025import org.onosproject.ui.UiTopoLayoutService;
Simon Hunt4f4ffc32016-08-03 18:30:47 -070026import org.onosproject.ui.model.topo.UiRegion;
Simon Huntf679c4e2016-04-01 17:02:24 -070027import org.onosproject.ui.model.topo.UiTopoLayout;
Thomas Vachuska4d66d0a2016-04-15 15:48:13 -070028import org.onosproject.ui.model.topo.UiTopoLayoutId;
Ray Milkeyd84f89b2018-08-17 14:54:17 -070029import org.osgi.service.component.annotations.Activate;
30import org.osgi.service.component.annotations.Component;
31import org.osgi.service.component.annotations.Deactivate;
32import org.osgi.service.component.annotations.Reference;
33import org.osgi.service.component.annotations.ReferenceCardinality;
Simon Huntf679c4e2016-04-01 17:02:24 -070034import org.slf4j.Logger;
35import org.slf4j.LoggerFactory;
36
Simon Huntb1ce2602016-07-23 14:04:31 -070037import java.util.Collections;
Simon Huntd0fa2842016-10-24 18:04:05 -070038import java.util.HashMap;
Simon Hunt4f4ffc32016-08-03 18:30:47 -070039import java.util.List;
Thomas Vachuska4d66d0a2016-04-15 15:48:13 -070040import java.util.Map;
Thomas Vachuska92b016b2016-05-20 11:37:57 -070041import java.util.Objects;
Thomas Vachuska4d66d0a2016-04-15 15:48:13 -070042import java.util.Set;
Thomas Vachuska92b016b2016-05-20 11:37:57 -070043import java.util.stream.Collectors;
44
45import static com.google.common.base.Preconditions.checkNotNull;
Thomas Vachuskaeb851cd2016-07-21 15:41:05 -070046import static org.onosproject.ui.model.topo.UiTopoLayoutId.DEFAULT_ID;
Simon Huntf679c4e2016-04-01 17:02:24 -070047
48/**
49 * Manages the user interface topology layouts.
50 * Note that these layouts are persisted and distributed across the cluster.
51 */
Ray Milkeyd84f89b2018-08-17 14:54:17 -070052@Component(immediate = true, service = UiTopoLayoutService.class)
Simon Huntf679c4e2016-04-01 17:02:24 -070053public class UiTopoLayoutManager implements UiTopoLayoutService {
54
Thomas Vachuska92b016b2016-05-20 11:37:57 -070055 private static final String ID_NULL = "Layout ID cannot be null";
56 private static final String LAYOUT_NULL = "Layout cannot be null";
57
Simon Huntd0fa2842016-10-24 18:04:05 -070058 private final Logger log = LoggerFactory.getLogger(getClass());
Thomas Vachuska4d66d0a2016-04-15 15:48:13 -070059
Simon Huntd0fa2842016-10-24 18:04:05 -070060 private final InternalConfigListener cfgListener = new InternalConfigListener();
61 private final Map<UiTopoLayoutId, UiTopoLayout> layoutMap = new HashMap<>();
62
Ray Milkeyd84f89b2018-08-17 14:54:17 -070063 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Simon Huntd0fa2842016-10-24 18:04:05 -070064 protected NetworkConfigRegistry cfgService;
65
Thomas Vachuska4d66d0a2016-04-15 15:48:13 -070066
Simon Huntf679c4e2016-04-01 17:02:24 -070067 @Activate
68 public void activate() {
Thomas Vachuska4d66d0a2016-04-15 15:48:13 -070069
Thomas Vachuska92b016b2016-05-20 11:37:57 -070070 // Create and add the default layout, if needed.
Simon Huntd0fa2842016-10-24 18:04:05 -070071 layoutMap.computeIfAbsent(DEFAULT_ID, UiTopoLayout::new);
72
73 cfgService.addListener(cfgListener);
74 cfgListener.initAllConfigs();
Thomas Vachuska92b016b2016-05-20 11:37:57 -070075
Simon Huntf679c4e2016-04-01 17:02:24 -070076 log.info("Started");
77 }
78
79 @Deactivate
80 public void deactivate() {
Simon Huntd0fa2842016-10-24 18:04:05 -070081 cfgService.removeListener(cfgListener);
82
Simon Huntf679c4e2016-04-01 17:02:24 -070083 log.info("Stopped");
84 }
85
86
87 @Override
Thomas Vachuska92b016b2016-05-20 11:37:57 -070088 public UiTopoLayout getRootLayout() {
89 return getLayout(DEFAULT_ID);
90 }
91
92 @Override
Thomas Vachuska4d66d0a2016-04-15 15:48:13 -070093 public Set<UiTopoLayout> getLayouts() {
94 return ImmutableSet.copyOf(layoutMap.values());
Simon Huntf679c4e2016-04-01 17:02:24 -070095 }
96
97 @Override
98 public boolean addLayout(UiTopoLayout layout) {
Thomas Vachuska92b016b2016-05-20 11:37:57 -070099 checkNotNull(layout, LAYOUT_NULL);
Simon Huntd0fa2842016-10-24 18:04:05 -0700100 return layoutMap.put(layout.id(), layout) == null;
Thomas Vachuska4d66d0a2016-04-15 15:48:13 -0700101 }
102
103 @Override
104 public UiTopoLayout getLayout(UiTopoLayoutId layoutId) {
Thomas Vachuska92b016b2016-05-20 11:37:57 -0700105 checkNotNull(layoutId, ID_NULL);
Thomas Vachuska4d66d0a2016-04-15 15:48:13 -0700106 return layoutMap.get(layoutId);
Simon Huntf679c4e2016-04-01 17:02:24 -0700107 }
108
109 @Override
Simon Hunt4f4ffc32016-08-03 18:30:47 -0700110 public UiTopoLayout getLayout(RegionId regionId) {
111 if (regionId == null || regionId.equals(UiRegion.NULL_ID)) {
112 return getRootLayout();
113 }
114
115 List<UiTopoLayout> matchingLayouts = layoutMap.values().stream()
116 .filter(l -> Objects.equals(regionId, l.regionId()))
117 .collect(Collectors.toList());
118 return matchingLayouts.isEmpty() ? null : matchingLayouts.get(0);
119 }
120
121 @Override
Simon Hunt98189192016-07-29 19:02:27 -0700122 public Set<UiTopoLayout> getPeerLayouts(UiTopoLayoutId layoutId) {
Simon Huntb1ce2602016-07-23 14:04:31 -0700123 checkNotNull(layoutId, ID_NULL);
Simon Hunt98189192016-07-29 19:02:27 -0700124
Simon Huntb1ce2602016-07-23 14:04:31 -0700125 UiTopoLayout layout = layoutMap.get(layoutId);
Simon Hunt98189192016-07-29 19:02:27 -0700126 if (layout == null || layout.isRoot()) {
Simon Huntb1ce2602016-07-23 14:04:31 -0700127 return Collections.emptySet();
128 }
129
130 UiTopoLayoutId parentId = layout.parent();
131 return layoutMap.values().stream()
Simon Hunte43cccebf2016-09-01 17:01:58 -0700132 // all layouts who are NOT me (or root) and who share my parent...
Simon Huntb1ce2602016-07-23 14:04:31 -0700133 .filter(l -> !Objects.equals(l.id(), layoutId) &&
Simon Hunte43cccebf2016-09-01 17:01:58 -0700134 !Objects.equals(l.id(), UiTopoLayoutId.DEFAULT_ID) &&
Simon Huntb1ce2602016-07-23 14:04:31 -0700135 Objects.equals(l.parent(), parentId))
136 .collect(Collectors.toSet());
137 }
138
139 @Override
Thomas Vachuska92b016b2016-05-20 11:37:57 -0700140 public Set<UiTopoLayout> getChildren(UiTopoLayoutId layoutId) {
141 checkNotNull(layoutId, ID_NULL);
142 return layoutMap.values().stream()
Simon Hunt98189192016-07-29 19:02:27 -0700143 .filter(l -> !l.isRoot() && Objects.equals(l.parent(), layoutId))
Thomas Vachuska92b016b2016-05-20 11:37:57 -0700144 .collect(Collectors.toSet());
145 }
146
147 @Override
Simon Huntf679c4e2016-04-01 17:02:24 -0700148 public boolean removeLayout(UiTopoLayout layout) {
Thomas Vachuska92b016b2016-05-20 11:37:57 -0700149 checkNotNull(layout, LAYOUT_NULL);
Simon Huntd0fa2842016-10-24 18:04:05 -0700150 return layoutMap.remove(layout.id()) != null;
Simon Huntf679c4e2016-04-01 17:02:24 -0700151 }
Thomas Vachuska4d66d0a2016-04-15 15:48:13 -0700152
Simon Huntd0fa2842016-10-24 18:04:05 -0700153 /*
154 * Listens for changes to layout configs, updating instances as necessary
155 */
156 private class InternalConfigListener implements NetworkConfigListener {
157
158 // look up the current config by layout ID and apply it
159 private void updateLayoutConfig(UiTopoLayoutId id) {
160 BasicUiTopoLayoutConfig cfg =
161 cfgService.getConfig(id, BasicUiTopoLayoutConfig.class);
162
163 log.info("Updating Layout via config... {}: {}", id, cfg);
164
165 UiTopoLayout layout = layoutMap.get(id);
166
167 // NOTE: if a value is null, then that null-ness should be set
168 // TODO: add setters on UiTopoLayout and implement...
169// layout
170// .region(cfg.region())
171// .parent(cfg.parent())
172// .geomap(cfg.geomap())
173// .sprites(cfg.sprites())
174// .scale(cfg.scale())
175// .offsetX(cfg.offsetX())
176// .offsetY(cfg.offsetY());
177 }
178
179 private void initAllConfigs() {
180 log.info("Initializing layout configurations...");
181 layoutMap.keySet().forEach(this::updateLayoutConfig);
182 }
183
184 @Override
185 public void event(NetworkConfigEvent event) {
186 UiTopoLayoutId id = (UiTopoLayoutId) event.subject();
187 updateLayoutConfig(id);
188 }
189
190 @Override
191 public boolean isRelevant(NetworkConfigEvent event) {
192 return (event.type() == NetworkConfigEvent.Type.CONFIG_ADDED ||
193 event.type() == NetworkConfigEvent.Type.CONFIG_UPDATED) &&
194 event.configClass().equals(BasicUiTopoLayoutConfig.class);
195 }
196 }
Simon Huntf679c4e2016-04-01 17:02:24 -0700197}