blob: bc32ac6bfb9468fcb3f7fe9f8e0a872e1943f471 [file] [log] [blame]
Thomas Vachuskafe8c98a2015-02-04 01:24:32 -08001/*
Brian O'Connora09fe5b2017-08-03 21:12:30 -07002 * Copyright 2015-present Open Networking Foundation
Thomas Vachuskafe8c98a2015-02-04 01:24:32 -08003 *
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 */
16package org.onosproject.ui;
17
Thomas Vachuskac4178cc2015-12-10 11:43:32 -080018import com.google.common.collect.ImmutableList;
Simon Hunt7379a3d2017-06-20 16:50:39 -070019import org.onosproject.ui.lion.LionBundle;
Thomas Vachuska3ccb9eb2015-04-29 23:33:56 -070020import org.slf4j.Logger;
21import org.slf4j.LoggerFactory;
Thomas Vachuskafe8c98a2015-02-04 01:24:32 -080022
23import java.io.InputStream;
Simon Hunte05cae42015-07-23 17:35:24 -070024import java.util.ArrayList;
Thomas Vachuskafe8c98a2015-02-04 01:24:32 -080025import java.util.List;
26
Simon Hunte05cae42015-07-23 17:35:24 -070027import static com.google.common.base.Preconditions.checkArgument;
Thomas Vachuskafe8c98a2015-02-04 01:24:32 -080028import static com.google.common.base.Preconditions.checkNotNull;
29
30/**
Simon Hunt8add9ee2016-09-20 17:05:07 -070031 * Immutable representation of a user interface extension.
32 * <p>
33 * Note that the {@link Builder} class is used to create a user
34 * interface extension instance, and that these instances are immutable.
Thomas Vachuskafe8c98a2015-02-04 01:24:32 -080035 */
Simon Hunte05cae42015-07-23 17:35:24 -070036public final class UiExtension {
Thomas Vachuskafe8c98a2015-02-04 01:24:32 -080037
Thomas Vachuska3ccb9eb2015-04-29 23:33:56 -070038 private final Logger log = LoggerFactory.getLogger(getClass());
39
Thomas Vachuska529db0a2015-02-23 16:42:14 -080040 private static final String VIEW_PREFIX = "app/view/";
Simon Hunte05cae42015-07-23 17:35:24 -070041 private static final String EMPTY = "";
42 private static final String SLASH = "/";
43 private static final String CSS_HTML = "css.html";
44 private static final String JS_HTML = "js.html";
Thomas Vachuska529db0a2015-02-23 16:42:14 -080045
Thomas Vachuskafe8c98a2015-02-04 01:24:32 -080046 private final ClassLoader classLoader;
Simon Hunte05cae42015-07-23 17:35:24 -070047 private final String resourcePath;
Simon Hunt8add9ee2016-09-20 17:05:07 -070048 private final List<UiView> viewList;
Simon Hunt7379a3d2017-06-20 16:50:39 -070049 private final List<LionBundle> lionBundles;
Thomas Vachuska3553b302015-03-07 14:49:43 -080050 private final UiMessageHandlerFactory messageHandlerFactory;
Simon Hunte05cae42015-07-23 17:35:24 -070051 private final UiTopoOverlayFactory topoOverlayFactory;
Simon Hunt22c35df2017-04-26 17:28:42 -070052 private final UiTopo2OverlayFactory topo2OverlayFactory;
Steven Burrows3a9a6442016-05-05 15:31:16 +010053 private final UiTopoMapFactory topoMapFactory;
Thomas Vachuskafe8c98a2015-02-04 01:24:32 -080054
Thomas Vachuskac4178cc2015-12-10 11:43:32 -080055 private boolean isValid = true;
Sean Condon13f42b72019-05-31 16:17:52 +010056 private boolean ui2Valid = true;
Simon Hunte05cae42015-07-23 17:35:24 -070057
58 // private constructor - only the builder calls this
59 private UiExtension(ClassLoader cl, String path, List<UiView> views,
Simon Hunt7379a3d2017-06-20 16:50:39 -070060 List<LionBundle> bundles,
Simon Hunte05cae42015-07-23 17:35:24 -070061 UiMessageHandlerFactory mhFactory,
Steven Burrows3a9a6442016-05-05 15:31:16 +010062 UiTopoOverlayFactory toFactory,
Simon Hunt22c35df2017-04-26 17:28:42 -070063 UiTopo2OverlayFactory to2Factory,
Sean Condon13f42b72019-05-31 16:17:52 +010064 UiTopoMapFactory tmFactory,
65 boolean ui2Vld) {
Simon Hunt8add9ee2016-09-20 17:05:07 -070066 classLoader = cl;
67 resourcePath = path;
68 viewList = views;
Simon Hunt7379a3d2017-06-20 16:50:39 -070069 lionBundles = bundles;
Simon Hunt8add9ee2016-09-20 17:05:07 -070070 messageHandlerFactory = mhFactory;
71 topoOverlayFactory = toFactory;
Simon Hunt22c35df2017-04-26 17:28:42 -070072 topo2OverlayFactory = to2Factory;
Simon Hunt8add9ee2016-09-20 17:05:07 -070073 topoMapFactory = tmFactory;
Sean Condon13f42b72019-05-31 16:17:52 +010074 ui2Valid = ui2Vld;
Thomas Vachuskafe8c98a2015-02-04 01:24:32 -080075 }
76
Thomas Vachuskafe8c98a2015-02-04 01:24:32 -080077
78 /**
79 * Returns input stream containing CSS inclusion statements.
80 *
81 * @return CSS inclusion statements
82 */
83 public InputStream css() {
Simon Hunte05cae42015-07-23 17:35:24 -070084 return getStream(resourcePath + CSS_HTML);
Thomas Vachuskafe8c98a2015-02-04 01:24:32 -080085 }
86
87 /**
88 * Returns input stream containing JavaScript inclusion statements.
89 *
90 * @return JavaScript inclusion statements
91 */
92 public InputStream js() {
Thomas Vachuskad894b5d2015-07-30 11:59:07 -070093 return getStream(resourcePath + JS_HTML);
Thomas Vachuskafe8c98a2015-02-04 01:24:32 -080094 }
95
96 /**
97 * Returns list of user interface views contributed by this extension.
98 *
99 * @return contributed view descriptors
100 */
101 public List<UiView> views() {
Sean Condon13f42b72019-05-31 16:17:52 +0100102 return (isValid || ui2Valid) ? viewList : ImmutableList.of();
Thomas Vachuskafe8c98a2015-02-04 01:24:32 -0800103 }
104
105 /**
Simon Hunt7379a3d2017-06-20 16:50:39 -0700106 * Returns the list of localization bundles that this extension is
107 * contributing.
108 *
109 * @return contributed localization bundles
110 */
111 public List<LionBundle> lionBundles() {
112 return ImmutableList.copyOf(lionBundles);
113 }
114
115 /**
Thomas Vachuskafe8c98a2015-02-04 01:24:32 -0800116 * Returns input stream containing specified view-specific resource.
117 *
118 * @param viewId view identifier
119 * @param path resource path, relative to the view directory
120 * @return resource input stream
121 */
122 public InputStream resource(String viewId, String path) {
Simon Hunte05cae42015-07-23 17:35:24 -0700123 return getStream(VIEW_PREFIX + viewId + SLASH + path);
Thomas Vachuskafe8c98a2015-02-04 01:24:32 -0800124 }
125
Thomas Vachuska3553b302015-03-07 14:49:43 -0800126 /**
Simon Hunte05cae42015-07-23 17:35:24 -0700127 * Returns message handler factory, if one was defined.
Thomas Vachuska3553b302015-03-07 14:49:43 -0800128 *
Simon Hunte05cae42015-07-23 17:35:24 -0700129 * @return message handler factory
Thomas Vachuska3553b302015-03-07 14:49:43 -0800130 */
131 public UiMessageHandlerFactory messageHandlerFactory() {
132 return messageHandlerFactory;
133 }
Thomas Vachuska3ccb9eb2015-04-29 23:33:56 -0700134
Simon Hunte05cae42015-07-23 17:35:24 -0700135 /**
136 * Returns the topology overlay factory, if one was defined.
137 *
138 * @return topology overlay factory
139 */
140 public UiTopoOverlayFactory topoOverlayFactory() {
141 return topoOverlayFactory;
142 }
143
Steven Burrows3a9a6442016-05-05 15:31:16 +0100144 /**
Simon Hunt22c35df2017-04-26 17:28:42 -0700145 * Returns the topology-2 overlay factory, if one was defined.
146 *
147 * @return topology-2 overlay factory
148 */
149 public UiTopo2OverlayFactory topo2OverlayFactory() {
150 return topo2OverlayFactory;
151 }
152
153 /**
Steven Burrows3a9a6442016-05-05 15:31:16 +0100154 * Returns the topology map factory, if one was defined.
155 *
156 * @return topology map factory
157 */
158 public UiTopoMapFactory topoMapFactory() {
159 return topoMapFactory;
160 }
161
Simon Hunte05cae42015-07-23 17:35:24 -0700162
Thomas Vachuska3ccb9eb2015-04-29 23:33:56 -0700163 // Returns the resource input stream from the specified class-loader.
164 private InputStream getStream(String path) {
165 InputStream stream = classLoader.getResourceAsStream(path);
166 if (stream == null) {
Thomas Vachuskac4178cc2015-12-10 11:43:32 -0800167 isValid = false;
Thomas Vachuska3ccb9eb2015-04-29 23:33:56 -0700168 log.warn("Unable to find resource {}", path);
169 }
170 return stream;
171 }
172
173
Simon Hunte05cae42015-07-23 17:35:24 -0700174 /**
175 * UI Extension Builder.
176 */
177 public static class Builder {
178 private ClassLoader classLoader;
179
180 private String resourcePath = EMPTY;
Simon Hunt8add9ee2016-09-20 17:05:07 -0700181 private List<UiView> viewList = new ArrayList<>();
Simon Hunt7379a3d2017-06-20 16:50:39 -0700182 private List<LionBundle> lionBundles = new ArrayList<>();
Simon Hunte05cae42015-07-23 17:35:24 -0700183 private UiMessageHandlerFactory messageHandlerFactory = null;
184 private UiTopoOverlayFactory topoOverlayFactory = null;
Simon Hunt22c35df2017-04-26 17:28:42 -0700185 private UiTopo2OverlayFactory topo2OverlayFactory = null;
Steven Burrows3a9a6442016-05-05 15:31:16 +0100186 private UiTopoMapFactory topoMapFactory = null;
Sean Condon13f42b72019-05-31 16:17:52 +0100187 private boolean ui2valid = false;
Simon Hunte05cae42015-07-23 17:35:24 -0700188
189 /**
190 * Create a builder with the given class loader.
191 * Resource path defaults to "".
192 * Views defaults to an empty list.
Simon Hunt8add9ee2016-09-20 17:05:07 -0700193 * MessageHandler, TopoOverlay, and TopoMap factories default to null.
Simon Hunte05cae42015-07-23 17:35:24 -0700194 *
Thomas Vachuskad894b5d2015-07-30 11:59:07 -0700195 * @param cl the class loader
196 * @param views list of views contributed by this extension
Simon Hunte05cae42015-07-23 17:35:24 -0700197 */
198 public Builder(ClassLoader cl, List<UiView> views) {
199 checkNotNull(cl, "Must provide a class loader");
Jon Hallcbd1b392017-01-18 20:15:44 -0800200 checkArgument(!views.isEmpty(), "Must provide at least one view");
Simon Hunt8add9ee2016-09-20 17:05:07 -0700201 classLoader = cl;
202 viewList = views;
Simon Hunte05cae42015-07-23 17:35:24 -0700203 }
204
205 /**
Simon Hunt7379a3d2017-06-20 16:50:39 -0700206 * Sets the localization bundles (aka {@code LionBundle}s) that this
207 * UI extension is contributing.
208 *
209 * @param bundles the bundles to register
210 * @return self, for chaining
211 */
212 public Builder lionBundles(List<LionBundle> bundles) {
213 checkNotNull(bundles, "Must provide a list");
214 lionBundles = bundles;
215 return this;
216 }
217
218 /**
Simon Hunt8add9ee2016-09-20 17:05:07 -0700219 * Set the resource path. That is, the path to where the CSS and JS
220 * files are located.
Simon Hunte05cae42015-07-23 17:35:24 -0700221 *
222 * @param path resource path
223 * @return self, for chaining
224 */
225 public Builder resourcePath(String path) {
Simon Hunt8add9ee2016-09-20 17:05:07 -0700226 resourcePath = path == null ? EMPTY : path + SLASH;
Simon Hunte05cae42015-07-23 17:35:24 -0700227 return this;
228 }
229
230 /**
231 * Sets the message handler factory for this extension.
232 *
233 * @param mhFactory message handler factory
234 * @return self, for chaining
235 */
236 public Builder messageHandlerFactory(UiMessageHandlerFactory mhFactory) {
Simon Hunt8add9ee2016-09-20 17:05:07 -0700237 messageHandlerFactory = mhFactory;
Simon Hunte05cae42015-07-23 17:35:24 -0700238 return this;
239 }
240
241 /**
242 * Sets the topology overlay factory for this extension.
243 *
244 * @param toFactory topology overlay factory
245 * @return self, for chaining
246 */
247 public Builder topoOverlayFactory(UiTopoOverlayFactory toFactory) {
Simon Hunt8add9ee2016-09-20 17:05:07 -0700248 topoOverlayFactory = toFactory;
Simon Hunte05cae42015-07-23 17:35:24 -0700249 return this;
250 }
251
252 /**
Simon Hunt22c35df2017-04-26 17:28:42 -0700253 * Sets the topology-2 overlay factory for this extension.
254 *
255 * @param to2Factory topology-2 overlay factory
256 * @return self, for chaining
257 */
258 public Builder topo2OverlayFactory(UiTopo2OverlayFactory to2Factory) {
259 topo2OverlayFactory = to2Factory;
260 return this;
261 }
262
263 /**
Steven Burrows3a9a6442016-05-05 15:31:16 +0100264 * Sets the topology map factory for this extension.
265 *
266 * @param tmFactory topology map factory
267 * @return self, for chaining
268 */
269 public Builder topoMapFactory(UiTopoMapFactory tmFactory) {
Simon Hunt8add9ee2016-09-20 17:05:07 -0700270 topoMapFactory = tmFactory;
Steven Burrows3a9a6442016-05-05 15:31:16 +0100271 return this;
272 }
273
274 /**
Sean Condon13f42b72019-05-31 16:17:52 +0100275 * Marks this as ui2valid for Ui2.
276 * This is because Ui2 does not include the same layout of embedded html, js and css
277 *
278 * @return self, for chaining
279 */
280 public Builder ui2() {
281 ui2valid = true;
282 return this;
283 }
284
285 /**
Simon Hunt8add9ee2016-09-20 17:05:07 -0700286 * Builds the user interface extension.
Simon Hunte05cae42015-07-23 17:35:24 -0700287 *
288 * @return UI extension instance
289 */
290 public UiExtension build() {
Simon Hunt8add9ee2016-09-20 17:05:07 -0700291 return new UiExtension(classLoader, resourcePath, viewList,
Simon Hunt7379a3d2017-06-20 16:50:39 -0700292 lionBundles,
Simon Hunt22c35df2017-04-26 17:28:42 -0700293 messageHandlerFactory, topoOverlayFactory,
Sean Condon13f42b72019-05-31 16:17:52 +0100294 topo2OverlayFactory, topoMapFactory, ui2valid);
Simon Hunte05cae42015-07-23 17:35:24 -0700295 }
Simon Hunte05cae42015-07-23 17:35:24 -0700296 }
Thomas Vachuskafe8c98a2015-02-04 01:24:32 -0800297}