AbstractResourceResolver.java
001 /*
002  * SPDX-License-Identifier: Apache-2.0
003  *
004  * Copyright 2008-2017 the original author or authors.
005  *
006  * Licensed under the Apache License, Version 2.0 (the "License");
007  * you may not use this file except in compliance with the License.
008  * You may obtain a copy of the License at
009  *
010  *     http://www.apache.org/licenses/LICENSE-2.0
011  *
012  * Unless required by applicable law or agreed to in writing, software
013  * distributed under the License is distributed on an "AS IS" BASIS,
014  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
015  * See the License for the specific language governing permissions and
016  * limitations under the License.
017  */
018 package org.codehaus.griffon.runtime.core.resources;
019 
020 import griffon.core.CallableWithArgs;
021 import griffon.core.resources.NoSuchResourceException;
022 import griffon.core.resources.ResourceResolver;
023 
024 import javax.annotation.Nonnull;
025 import javax.annotation.Nullable;
026 import java.beans.PropertyEditor;
027 import java.text.MessageFormat;
028 import java.util.List;
029 import java.util.Locale;
030 import java.util.Map;
031 import java.util.MissingResourceException;
032 
033 import static griffon.core.editors.PropertyEditorResolver.findEditor;
034 import static griffon.util.GriffonNameUtils.requireNonBlank;
035 import static java.util.Objects.requireNonNull;
036 
037 /**
038  @author Andres Almiray
039  @since 2.0.0
040  */
041 public abstract class AbstractResourceResolver implements ResourceResolver {
042     protected static final String ERROR_KEY_BLANK = "Argument 'key' must not be blank";
043     protected static final String ERROR_LOCALE_NULL = "Argument 'locale' must not be null";
044     protected static final String ERROR_ARGS_NULL = "Argument 'args' must not be null";
045     protected static final String ERROR_RESOURCE_NULL = "Argument 'resource' must not be null";
046 
047     protected static final Object[] EMPTY_OBJECT_ARGS = new Object[0];
048 
049     @Nonnull
050     @Override
051     public Object resolveResource(@Nonnull String keythrows NoSuchResourceException {
052         return resolveResource(key, EMPTY_OBJECT_ARGS, Locale.getDefault());
053     }
054 
055     @Nonnull
056     @Override
057     public Object resolveResource(@Nonnull String key, @Nonnull Locale localethrows NoSuchResourceException {
058         return resolveResource(key, EMPTY_OBJECT_ARGS, locale);
059     }
060 
061     @Nonnull
062     @Override
063     public Object resolveResource(@Nonnull String key, @Nonnull Object[] argsthrows NoSuchResourceException {
064         return resolveResource(key, args, Locale.getDefault());
065     }
066 
067     @Nonnull
068     @Override
069     public Object resolveResource(@Nonnull String key, @Nonnull Object[] args, @Nonnull Locale localethrows NoSuchResourceException {
070         requireNonBlank(key, ERROR_KEY_BLANK);
071         requireNonNull(args, ERROR_ARGS_NULL);
072         requireNonNull(locale, ERROR_LOCALE_NULL);
073         Object resource = resolveResourceValue(key, locale);
074         Object result = evalResourceWithArguments(resource, args);
075         if (result != nullreturn result;
076         throw new NoSuchResourceException(key, locale);
077     }
078 
079     @Nonnull
080     @Override
081     public Object resolveResource(@Nonnull String key, @Nonnull List<?> argsthrows NoSuchResourceException {
082         return resolveResource(key, toObjectArray(args), Locale.getDefault());
083     }
084 
085     @Nonnull
086     @Override
087     public Object resolveResource(@Nonnull String key, @Nonnull List<?> args, @Nonnull Locale localethrows NoSuchResourceException {
088         return resolveResource(key, toObjectArray(args), locale);
089     }
090 
091     @Nullable
092     @Override
093     public Object resolveResource(@Nonnull String key, @Nullable Object defaultValue) {
094         return resolveResource(key, EMPTY_OBJECT_ARGS, Locale.getDefault(), defaultValue);
095     }
096 
097     @Nullable
098     @Override
099     public Object resolveResource(@Nonnull String key, @Nonnull Locale locale, @Nullable Object defaultValue) {
100         return resolveResource(key, EMPTY_OBJECT_ARGS, locale, defaultValue);
101     }
102 
103     @Nullable
104     @Override
105     public Object resolveResource(@Nonnull String key, @Nonnull Object[] args, @Nullable Object defaultValue) {
106         return resolveResource(key, args, Locale.getDefault(), defaultValue);
107     }
108 
109     @Nullable
110     @Override
111     public Object resolveResource(@Nonnull String key, @Nonnull Object[] args, @Nonnull Locale locale, @Nullable Object defaultValue) {
112         try {
113             return resolveResource(key, args, locale);
114         catch (NoSuchResourceException nsre) {
115             return null == defaultValue ? key : defaultValue;
116         }
117     }
118 
119     @Nullable
120     @Override
121     public Object resolveResource(@Nonnull String key, @Nonnull List<?> args, @Nullable Object defaultValue) {
122         return resolveResource(key, toObjectArray(args), Locale.getDefault(), defaultValue);
123     }
124 
125     @Nullable
126     @Override
127     public Object resolveResource(@Nonnull String key, @Nonnull List<?> args, @Nonnull Locale locale, @Nullable Object defaultValue) {
128         return resolveResource(key, toObjectArray(args), locale, defaultValue);
129     }
130 
131     @Nonnull
132     @Override
133     public Object resolveResource(@Nonnull String key, @Nonnull Map<String, Object> argsthrows NoSuchResourceException {
134         return resolveResource(key, args, Locale.getDefault());
135     }
136 
137     @Nonnull
138     @Override
139     public Object resolveResource(@Nonnull String key, @Nonnull Map<String, Object> args, @Nonnull Locale localethrows NoSuchResourceException {
140         requireNonBlank(key, ERROR_KEY_BLANK);
141         requireNonNull(args, ERROR_ARGS_NULL);
142         requireNonNull(locale, ERROR_LOCALE_NULL);
143         Object resource = resolveResourceValue(key, locale);
144         Object result = evalResourceWithArguments(resource, args);
145         if (result != nullreturn result;
146         throw new NoSuchResourceException(key, locale);
147     }
148 
149     @Nullable
150     @Override
151     public Object resolveResource(@Nonnull String key, @Nonnull Map<String, Object> args, @Nullable Object defaultValue) {
152         return resolveResource(key, args, Locale.getDefault(), defaultValue);
153     }
154 
155     @Nullable
156     @Override
157     public Object resolveResource(@Nonnull String key, @Nonnull Map<String, Object> args, @Nonnull Locale locale, @Nullable Object defaultValue) {
158         try {
159             return resolveResource(key, args, locale);
160         catch (NoSuchResourceException nsre) {
161             return null == defaultValue ? key : defaultValue;
162         }
163     }
164 
165     @Nullable
166     @Override
167     public <T> T resolveResourceConverted(@Nonnull String key, @Nonnull List<?> args, @Nullable T defaultValue, @Nonnull Class<T> type) {
168         return convertValue(resolveResource(key, args, defaultValue), type);
169     }
170 
171     @Nullable
172     @Override
173     public <T> T resolveResourceConverted(@Nonnull String key, @Nonnull List<?> args, @Nonnull Locale locale, @Nullable T defaultValue, @Nonnull Class<T> type) {
174         return convertValue(resolveResource(key, args, locale, defaultValue), type);
175     }
176 
177     @Nonnull
178     @Override
179     public <T> T resolveResourceConverted(@Nonnull String key, @Nonnull List<?> args, @Nonnull Locale locale, @Nonnull Class<T> typethrows NoSuchResourceException {
180         return convertValue(resolveResource(key, args, locale), type);
181     }
182 
183     @Nonnull
184     @Override
185     public <T> T resolveResourceConverted(@Nonnull String key, @Nonnull List<?> args, @Nonnull Class<T> typethrows NoSuchResourceException {
186         return convertValue(resolveResource(key, args), type);
187     }
188 
189     @Nullable
190     @Override
191     public <T> T resolveResourceConverted(@Nonnull String key, @Nonnull Map<String, Object> args, @Nullable T defaultValue, @Nonnull Class<T> type) {
192         return convertValue(resolveResource(key, args, defaultValue), type);
193     }
194 
195     @Nullable
196     @Override
197     public <T> T resolveResourceConverted(@Nonnull String key, @Nonnull Map<String, Object> args, @Nonnull Locale locale, @Nullable T defaultValue, @Nonnull Class<T> type) {
198         return convertValue(resolveResource(key, args, locale, defaultValue), type);
199     }
200 
201     @Nonnull
202     @Override
203     public <T> T resolveResourceConverted(@Nonnull String key, @Nonnull Map<String, Object> args, @Nonnull Locale locale, @Nonnull Class<T> typethrows NoSuchResourceException {
204         return convertValue(resolveResource(key, args, locale), type);
205     }
206 
207     @Nonnull
208     @Override
209     public <T> T resolveResourceConverted(@Nonnull String key, @Nonnull Map<String, Object> args, @Nonnull Class<T> typethrows NoSuchResourceException {
210         return convertValue(resolveResource(key, args), type);
211     }
212 
213     @Nullable
214     @Override
215     public <T> T resolveResourceConverted(@Nonnull String key, @Nonnull Object[] args, @Nullable T defaultValue, @Nonnull Class<T> type) {
216         return convertValue(resolveResource(key, args, defaultValue), type);
217     }
218 
219     @Nullable
220     @Override
221     public <T> T resolveResourceConverted(@Nonnull String key, @Nonnull Object[] args, @Nonnull Locale locale, @Nullable T defaultValue, @Nonnull Class<T> type) {
222         return convertValue(resolveResource(key, args, locale, defaultValue), type);
223     }
224 
225     @Nonnull
226     @Override
227     public <T> T resolveResourceConverted(@Nonnull String key, @Nonnull Object[] args, @Nonnull Locale locale, @Nonnull Class<T> typethrows NoSuchResourceException {
228         return convertValue(resolveResource(key, args, locale), type);
229     }
230 
231     @Nonnull
232     @Override
233     public <T> T resolveResourceConverted(@Nonnull String key, @Nonnull Object[] args, @Nonnull Class<T> typethrows NoSuchResourceException {
234         return convertValue(resolveResource(key, args), type);
235     }
236 
237     @Nullable
238     @Override
239     public <T> T resolveResourceConverted(@Nonnull String key, @Nullable T defaultValue, @Nonnull Class<T> type) {
240         return convertValue(resolveResource(key, defaultValue), type);
241     }
242 
243     @Nullable
244     @Override
245     public <T> T resolveResourceConverted(@Nonnull String key, @Nonnull Locale locale, @Nullable T defaultValue, @Nonnull Class<T> type) {
246         return convertValue(resolveResource(key, locale, defaultValue), type);
247     }
248 
249     @Nonnull
250     @Override
251     public <T> T resolveResourceConverted(@Nonnull String key, @Nonnull Locale locale, @Nonnull Class<T> typethrows NoSuchResourceException {
252         return convertValue(resolveResource(key, locale), type);
253     }
254 
255     @Nonnull
256     @Override
257     public <T> T resolveResourceConverted(@Nonnull String key, @Nonnull Class<T> typethrows NoSuchResourceException {
258         return convertValue(resolveResource(key), type);
259     }
260 
261     @Nonnull
262     @Override
263     public Object resolveResourceValue(@Nonnull String key, @Nonnull Locale localethrows NoSuchResourceException {
264         requireNonBlank(key, ERROR_KEY_BLANK);
265         requireNonNull(locale, ERROR_LOCALE_NULL);
266         try {
267             Object resource = doResolveResourceValue(key, locale);
268             if (resource instanceof CharSequence) {
269                 String msg = resource.toString();
270                 if (msg.length() >= && msg.startsWith(REF_KEY_START&& msg.endsWith(REF_KEY_END)) {
271                     String refKey = msg.substring(2, msg.length() 1);
272                     resource = resolveResourceValue(refKey, locale);
273                 }
274             }
275             return resource;
276         catch (MissingResourceException mre) {
277             throw new NoSuchResourceException(key, locale);
278         }
279     }
280 
281     @Nonnull
282     @Override
283     public String formatResource(@Nonnull String resource, @Nonnull List<?> args) {
284         requireNonNull(resource, ERROR_RESOURCE_NULL);
285         requireNonNull(args, ERROR_ARGS_NULL);
286         return formatResource(resource, args.toArray(new Object[args.size()]));
287     }
288 
289     @Nonnull
290     @Override
291     public String formatResource(@Nonnull String resource, @Nonnull Object[] args) {
292         requireNonNull(resource, ERROR_RESOURCE_NULL);
293         requireNonNull(args, ERROR_ARGS_NULL);
294         if (args.length == 0return resource;
295         return MessageFormat.format(resource, args);
296     }
297 
298     @Nonnull
299     @Override
300     public String formatResource(@Nonnull String resource, @Nonnull Map<String, Object> args) {
301         requireNonNull(resource, ERROR_RESOURCE_NULL);
302         requireNonNull(args, ERROR_ARGS_NULL);
303         for (Map.Entry<String, Object> variable : args.entrySet()) {
304             String var = variable.getKey();
305             String value = variable.getValue() != null ? variable.getValue().toString() null;
306             if (value != null) {
307                 resource = resource.replace("{:" + var + "}", value);
308             }
309         }
310         return resource;
311     }
312 
313     @Nonnull
314     protected abstract Object doResolveResourceValue(@Nonnull String key, @Nonnull Locale localethrows NoSuchResourceException;
315 
316     @Nullable
317     protected Object evalResourceWithArguments(@Nonnull Object resource, @Nonnull Object[] args) {
318         if (resource instanceof CallableWithArgs) {
319             CallableWithArgs<?> callable = (CallableWithArgs<?>resource;
320             return callable.call(args);
321         else if (resource instanceof CharSequence) {
322             return formatResource(String.valueOf(resource), args);
323         }
324         return resource;
325     }
326 
327     @Nullable
328     protected Object evalResourceWithArguments(@Nonnull Object resource, @Nonnull Map<String, Object> args) {
329         if (resource instanceof CallableWithArgs) {
330             CallableWithArgs<?> callable = (CallableWithArgs<?>resource;
331             return callable.call(args);
332         else if (resource instanceof CharSequence) {
333             return formatResource(String.valueOf(resource), args);
334         }
335         return resource;
336     }
337 
338     @Nonnull
339     protected Object[] toObjectArray(@Nonnull List<?> args) {
340         if (args.isEmpty()) {
341             return EMPTY_OBJECT_ARGS;
342         }
343         return args.toArray(new Object[args.size()]);
344     }
345 
346     @SuppressWarnings("unchecked")
347     protected <T> T convertValue(@Nullable Object value, @Nonnull Class<T> type) {
348         if (value != null) {
349             if (type.isAssignableFrom(value.getClass())) {
350                 return (Tvalue;
351             else {
352                 PropertyEditor editor = findEditor(type);
353                 editor.setValue(value);
354                 return (Teditor.getValue();
355             }
356         }
357         return null;
358     }
359 }