blob: b6671b84433bfc54c3dcd5953ddd0a2cca537228 [file] [log] [blame]
Simon Hunt00b369a2017-06-20 19:46:40 -07001/*
2 * Copyright 2017-present Open Networking Laboratory
3 *
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 */
17
18package org.onosproject.ui.impl.lion;
19
20import com.google.common.collect.ImmutableList;
21import org.onosproject.ui.lion.LionBundle;
Simon Hunt00b369a2017-06-20 19:46:40 -070022import org.slf4j.Logger;
23import org.slf4j.LoggerFactory;
24
25import java.util.ArrayList;
26import java.util.List;
Simon Hunte6c55dd2017-06-21 14:33:02 -070027import java.util.Locale;
Simon Huntd8754652017-06-21 11:45:22 -070028import java.util.MissingResourceException;
Simon Hunt00b369a2017-06-20 19:46:40 -070029import java.util.ResourceBundle;
30import java.util.Set;
31
32/**
33 * Gathers and stitches together a localization bundle according to a
34 * "lion" configuration file.
35 */
36public class BundleStitcher {
37
38 private static final Logger log =
39 LoggerFactory.getLogger(BundleStitcher.class);
40
41 private static final String CONFIG_DIR = "_config";
42 private static final String SUFFIX = ".lioncfg";
43 private static final String SLASH = "/";
44 private static final String DOT = ".";
45
46
47 private final String base;
48
49 /**
50 * Creates a bundle stitcher, configured with the specified base resource
51 * path.
52 *
53 * @param base the base resource path
54 */
55 public BundleStitcher(String base) {
56 this.base = base;
57 }
58
59 @Override
60 public String toString() {
61 return "BundleStitcher{base=\"" + base + "\"}";
62 }
63
64 /**
65 * Stitches together a LionBundle, based on the bundle configuration data
66 * for the given bundle ID.
67 *
68 * @param id the bundle ID
69 * @return a corresponding lion bundle
Simon Huntd8754652017-06-21 11:45:22 -070070 * @throws IllegalArgumentException if the config cannot be loaded
71 * or the bundle cannot be stitched
Simon Hunt00b369a2017-06-20 19:46:40 -070072 */
73 public LionBundle stitch(String id) {
74 String source = base + SLASH + CONFIG_DIR + SLASH + id + SUFFIX;
Simon Huntd8754652017-06-21 11:45:22 -070075
76 // the following may throw IllegalArgumentException...
Simon Hunt00b369a2017-06-20 19:46:40 -070077 LionConfig cfg = new LionConfig().load(source);
Simon Huntd8754652017-06-21 11:45:22 -070078
Simon Hunt00b369a2017-06-20 19:46:40 -070079 LionBundle.Builder builder = new LionBundle.Builder(id);
Simon Huntd8754652017-06-21 11:45:22 -070080 int total = 0;
81 int added = 0;
Simon Hunt00b369a2017-06-20 19:46:40 -070082
83 for (LionConfig.CmdFrom from : cfg.entries()) {
Simon Huntd8754652017-06-21 11:45:22 -070084 total += 1;
85 log.debug(" processing: {}", from.orig());
86 if (addItemsToBuilder(builder, from)) {
87 added += 1;
88 }
Simon Hunt00b369a2017-06-20 19:46:40 -070089 }
Simon Huntd8754652017-06-21 11:45:22 -070090 log.debug(" added items for {}/{} FROM entries", added, total);
Simon Hunt00b369a2017-06-20 19:46:40 -070091 return builder.build();
92 }
93
Simon Huntd8754652017-06-21 11:45:22 -070094 private boolean addItemsToBuilder(LionBundle.Builder builder,
95 LionConfig.CmdFrom from) {
Simon Hunt00b369a2017-06-20 19:46:40 -070096 String resBundleName = base + SLASH + from.res();
Simon Hunte6c55dd2017-06-21 14:33:02 -070097 String fqbn = convertToFqbn(resBundleName);
Simon Huntd8754652017-06-21 11:45:22 -070098 ResourceBundle bundle = null;
99 boolean ok = true;
Simon Hunt00b369a2017-06-20 19:46:40 -0700100
Simon Huntd8754652017-06-21 11:45:22 -0700101 try {
Simon Hunte6c55dd2017-06-21 14:33:02 -0700102 // NOTE: have to be explicit about the locale and class-loader
103 // for this to work under Karaf, apparently...
104 Locale locale = Locale.getDefault();
105 ClassLoader classLoader = getClass().getClassLoader();
106 bundle = ResourceBundle.getBundle(fqbn, locale, classLoader);
107
Simon Huntd8754652017-06-21 11:45:22 -0700108 } catch (MissingResourceException e) {
Simon Hunte6c55dd2017-06-21 14:33:02 -0700109 log.warn("Cannot find resource bundle: {}", fqbn);
Simon Huntd8754652017-06-21 11:45:22 -0700110 log.debug("BOOM!", e);
111 ok = false;
Simon Hunt00b369a2017-06-20 19:46:40 -0700112 }
Simon Huntd8754652017-06-21 11:45:22 -0700113
114 if (ok) {
115 Set<String> keys = from.starred() ? bundle.keySet() : from.keys();
116 addItems(builder, bundle, keys);
117 log.debug(" added {} item(s) from {}", keys.size(), from.res());
118 }
119
120 return ok;
Simon Hunt00b369a2017-06-20 19:46:40 -0700121 }
122
123 // to fully-qualified-bundle-name
124 private String convertToFqbn(String path) {
125 if (!path.startsWith(SLASH)) {
126 throw new IllegalArgumentException("path should start with '/'");
127 }
128 return path.substring(1).replaceAll(SLASH, DOT);
129 }
130
Simon Hunt00b369a2017-06-20 19:46:40 -0700131 private void addItems(LionBundle.Builder builder, ResourceBundle bundle,
132 Set<String> keys) {
133 keys.forEach(k -> builder.addItem(k, bundle.getString(k)));
134 }
135
136 /**
137 * Generates an immutable list of localization bundles, using the specified
138 * resource tree (base) and localization configuration file names (tags).
139 * <p>
140 * As an example, you might invoke:
141 * <pre>
142 * private static final String LION_BASE = "/org/onosproject/ui/lion";
143 *
144 * private static final String[] LION_TAGS = {
145 * "core.view.App",
146 * "core.view.Settings",
147 * "core.view.Cluster",
148 * "core.view.Processor",
149 * "core.view.Partition",
150 * };
151 *
152 * List&lt;LionBundle&gt; bundles =
153 * LionUtils.generateBundles(LION_BASE, LION_TAGS);
154 * </pre>
155 * It is expected that in the "LION_BASE" directory there is a subdirectory
156 * named "_config" which contains the configuration files listed in the
157 * "LION_TAGS" array, each with a ".lioncfg" suffix...
158 * <pre>
159 * /org/onosproject/ui/lion/
160 * |
161 * +-- _config
162 * |
163 * +-- core.view.App.lioncfg
164 * +-- core.view.Settings.lioncfg
165 * :
166 * </pre>
167 * These files collate a localization bundle for their particular view
168 * by referencing resource bundles and their keys.
169 *
170 * @param base the base resource directory path
171 * @param tags the list of bundles to generate
172 * @return a list of generated localization bundles
173 */
Simon Huntd8754652017-06-21 11:45:22 -0700174 public static List<LionBundle> generateBundles(String base, String... tags) {
175 List<LionBundle> bundles = new ArrayList<>(tags.length);
Simon Hunt00b369a2017-06-20 19:46:40 -0700176 BundleStitcher stitcher = new BundleStitcher(base);
177 for (String tag : tags) {
178 try {
Simon Huntd8754652017-06-21 11:45:22 -0700179 LionBundle lion = stitcher.stitch(tag);
180 bundles.add(lion);
181 log.info("Generated LION bundle: {}", lion);
Simon Hunte6c55dd2017-06-21 14:33:02 -0700182 log.debug(" Dumped: {}", lion.dump());
Simon Hunt00b369a2017-06-20 19:46:40 -0700183
184 } catch (IllegalArgumentException e) {
185 log.warn("Unable to generate bundle: {} / {}", base, tag);
Simon Huntd8754652017-06-21 11:45:22 -0700186 log.debug("BOOM!", e);
Simon Hunt00b369a2017-06-20 19:46:40 -0700187 }
188 }
Simon Huntd8754652017-06-21 11:45:22 -0700189 return ImmutableList.copyOf(bundles);
Simon Hunt00b369a2017-06-20 19:46:40 -0700190 }
191}