blob: f2fa27e2b5fb8c5e9dd53fb1accbb4dceb81331b [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 Hunt7648cac2017-06-22 08:58:19 -070022import org.onosproject.ui.lion.LionUtils;
Simon Hunt00b369a2017-06-20 19:46:40 -070023import org.slf4j.Logger;
24import org.slf4j.LoggerFactory;
25
26import java.util.ArrayList;
27import java.util.List;
Simon Hunte6c55dd2017-06-21 14:33:02 -070028import java.util.Locale;
Simon Huntd8754652017-06-21 11:45:22 -070029import java.util.MissingResourceException;
Simon Hunt00b369a2017-06-20 19:46:40 -070030import java.util.ResourceBundle;
31import java.util.Set;
32
33/**
34 * Gathers and stitches together a localization bundle according to a
35 * "lion" configuration file.
36 */
37public class BundleStitcher {
38
39 private static final Logger log =
40 LoggerFactory.getLogger(BundleStitcher.class);
41
42 private static final String CONFIG_DIR = "_config";
43 private static final String SUFFIX = ".lioncfg";
44 private static final String SLASH = "/";
45 private static final String DOT = ".";
46
47
48 private final String base;
49
50 /**
51 * Creates a bundle stitcher, configured with the specified base resource
52 * path.
53 *
54 * @param base the base resource path
55 */
56 public BundleStitcher(String base) {
57 this.base = base;
58 }
59
60 @Override
61 public String toString() {
62 return "BundleStitcher{base=\"" + base + "\"}";
63 }
64
65 /**
66 * Stitches together a LionBundle, based on the bundle configuration data
67 * for the given bundle ID.
68 *
69 * @param id the bundle ID
70 * @return a corresponding lion bundle
Simon Huntd8754652017-06-21 11:45:22 -070071 * @throws IllegalArgumentException if the config cannot be loaded
72 * or the bundle cannot be stitched
Simon Hunt00b369a2017-06-20 19:46:40 -070073 */
74 public LionBundle stitch(String id) {
75 String source = base + SLASH + CONFIG_DIR + SLASH + id + SUFFIX;
Simon Huntd8754652017-06-21 11:45:22 -070076
77 // the following may throw IllegalArgumentException...
Simon Hunt00b369a2017-06-20 19:46:40 -070078 LionConfig cfg = new LionConfig().load(source);
Simon Huntd8754652017-06-21 11:45:22 -070079
Simon Hunt00b369a2017-06-20 19:46:40 -070080 LionBundle.Builder builder = new LionBundle.Builder(id);
Simon Huntd8754652017-06-21 11:45:22 -070081 int total = 0;
82 int added = 0;
Simon Hunt00b369a2017-06-20 19:46:40 -070083
84 for (LionConfig.CmdFrom from : cfg.entries()) {
Simon Huntd8754652017-06-21 11:45:22 -070085 total += 1;
86 log.debug(" processing: {}", from.orig());
87 if (addItemsToBuilder(builder, from)) {
88 added += 1;
89 }
Simon Hunt00b369a2017-06-20 19:46:40 -070090 }
Simon Huntd8754652017-06-21 11:45:22 -070091 log.debug(" added items for {}/{} FROM entries", added, total);
Simon Hunt00b369a2017-06-20 19:46:40 -070092 return builder.build();
93 }
94
Simon Huntd8754652017-06-21 11:45:22 -070095 private boolean addItemsToBuilder(LionBundle.Builder builder,
96 LionConfig.CmdFrom from) {
Simon Hunt00b369a2017-06-20 19:46:40 -070097 String resBundleName = base + SLASH + from.res();
Simon Hunte6c55dd2017-06-21 14:33:02 -070098 String fqbn = convertToFqbn(resBundleName);
Simon Huntd8754652017-06-21 11:45:22 -070099 ResourceBundle bundle = null;
100 boolean ok = true;
Simon Hunt00b369a2017-06-20 19:46:40 -0700101
Simon Huntd8754652017-06-21 11:45:22 -0700102 try {
Simon Hunte6c55dd2017-06-21 14:33:02 -0700103 // NOTE: have to be explicit about the locale and class-loader
104 // for this to work under Karaf, apparently...
105 Locale locale = Locale.getDefault();
106 ClassLoader classLoader = getClass().getClassLoader();
Simon Hunt7648cac2017-06-22 08:58:19 -0700107 bundle = LionUtils.getBundledResource(fqbn, locale, classLoader);
Simon Hunte6c55dd2017-06-21 14:33:02 -0700108
Simon Huntd8754652017-06-21 11:45:22 -0700109 } catch (MissingResourceException e) {
Simon Hunte6c55dd2017-06-21 14:33:02 -0700110 log.warn("Cannot find resource bundle: {}", fqbn);
Simon Huntd8754652017-06-21 11:45:22 -0700111 log.debug("BOOM!", e);
112 ok = false;
Simon Hunt00b369a2017-06-20 19:46:40 -0700113 }
Simon Huntd8754652017-06-21 11:45:22 -0700114
115 if (ok) {
116 Set<String> keys = from.starred() ? bundle.keySet() : from.keys();
117 addItems(builder, bundle, keys);
118 log.debug(" added {} item(s) from {}", keys.size(), from.res());
119 }
120
121 return ok;
Simon Hunt00b369a2017-06-20 19:46:40 -0700122 }
123
124 // to fully-qualified-bundle-name
125 private String convertToFqbn(String path) {
126 if (!path.startsWith(SLASH)) {
127 throw new IllegalArgumentException("path should start with '/'");
128 }
129 return path.substring(1).replaceAll(SLASH, DOT);
130 }
131
Simon Hunt00b369a2017-06-20 19:46:40 -0700132 private void addItems(LionBundle.Builder builder, ResourceBundle bundle,
133 Set<String> keys) {
134 keys.forEach(k -> builder.addItem(k, bundle.getString(k)));
135 }
136
137 /**
138 * Generates an immutable list of localization bundles, using the specified
139 * resource tree (base) and localization configuration file names (tags).
140 * <p>
141 * As an example, you might invoke:
142 * <pre>
143 * private static final String LION_BASE = "/org/onosproject/ui/lion";
144 *
145 * private static final String[] LION_TAGS = {
146 * "core.view.App",
147 * "core.view.Settings",
148 * "core.view.Cluster",
149 * "core.view.Processor",
150 * "core.view.Partition",
151 * };
152 *
153 * List&lt;LionBundle&gt; bundles =
154 * LionUtils.generateBundles(LION_BASE, LION_TAGS);
155 * </pre>
156 * It is expected that in the "LION_BASE" directory there is a subdirectory
157 * named "_config" which contains the configuration files listed in the
158 * "LION_TAGS" array, each with a ".lioncfg" suffix...
159 * <pre>
160 * /org/onosproject/ui/lion/
161 * |
162 * +-- _config
163 * |
164 * +-- core.view.App.lioncfg
165 * +-- core.view.Settings.lioncfg
166 * :
167 * </pre>
168 * These files collate a localization bundle for their particular view
169 * by referencing resource bundles and their keys.
170 *
171 * @param base the base resource directory path
172 * @param tags the list of bundles to generate
173 * @return a list of generated localization bundles
174 */
Simon Huntd8754652017-06-21 11:45:22 -0700175 public static List<LionBundle> generateBundles(String base, String... tags) {
176 List<LionBundle> bundles = new ArrayList<>(tags.length);
Simon Hunt00b369a2017-06-20 19:46:40 -0700177 BundleStitcher stitcher = new BundleStitcher(base);
178 for (String tag : tags) {
179 try {
Simon Huntd8754652017-06-21 11:45:22 -0700180 LionBundle lion = stitcher.stitch(tag);
181 bundles.add(lion);
182 log.info("Generated LION bundle: {}", lion);
Simon Hunte6c55dd2017-06-21 14:33:02 -0700183 log.debug(" Dumped: {}", lion.dump());
Simon Hunt00b369a2017-06-20 19:46:40 -0700184
185 } catch (IllegalArgumentException e) {
186 log.warn("Unable to generate bundle: {} / {}", base, tag);
Simon Huntd8754652017-06-21 11:45:22 -0700187 log.debug("BOOM!", e);
Simon Hunt00b369a2017-06-20 19:46:40 -0700188 }
189 }
Simon Huntd8754652017-06-21 11:45:22 -0700190 return ImmutableList.copyOf(bundles);
Simon Hunt00b369a2017-06-20 19:46:40 -0700191 }
192}