001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one or more
003: * contributor license agreements. See the NOTICE file distributed with
004: * this work for additional information regarding copyright ownership.
005: * The ASF licenses this file to You under the Apache License, Version 2.0
006: * (the "License"); you may not use this file except in compliance with
007: * the License. You may obtain a copy of the License at
008: *
009: * http://www.apache.org/licenses/LICENSE-2.0
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: * See the License for the specific language governing permissions and
015: * limitations under the License.
016: */
017: package org.apache.wicket;
018:
019: import java.lang.ref.WeakReference;
020: import java.util.HashMap;
021: import java.util.Locale;
022: import java.util.Map;
023: import java.util.WeakHashMap;
024:
025: import org.apache.wicket.util.file.Files;
026: import org.apache.wicket.util.string.AppendingStringBuffer;
027: import org.slf4j.Logger;
028: import org.slf4j.LoggerFactory;
029:
030: /**
031: * Class which holds shared resources. Resources can be shared by name. An
032: * optional scope can be given to prevent naming conflicts and a locale and/or
033: * style can be given as well.
034: *
035: * @author Jonathan Locke
036: * @author Johan Compagner
037: * @author Gili Tzabari
038: */
039: public class SharedResources {
040: /** Logger */
041: private static final Logger log = LoggerFactory
042: .getLogger(SharedResources.class);
043:
044: /**
045: * THIS METHOD IS NOT PART OF THE WICKET PUBLIC API. DO NOT CALL IT. Inserts
046: * _[locale] and _[style] into path just before any extension that might
047: * exist.
048: *
049: * @param path
050: * The resource path
051: * @param locale
052: * The locale
053: * @param style
054: * The style (see {@link org.apache.wicket.Session})
055: * @return The localized path
056: */
057: public static String resourceKey(final String path,
058: final Locale locale, final String style) {
059: final String extension = Files.extension(path);
060: final String basePath = Files.basePath(path, extension);
061: final AppendingStringBuffer buffer = new AppendingStringBuffer(
062: basePath.length() + 16);
063: buffer.append(basePath);
064:
065: // First style because locale can append later on.
066: if (style != null) {
067: buffer.append('_');
068: buffer.append(style);
069: }
070: if (locale != null) {
071: buffer.append('_');
072: boolean l = locale.getLanguage().length() != 0;
073: boolean c = locale.getCountry().length() != 0;
074: boolean v = locale.getVariant().length() != 0;
075: buffer.append(locale.getLanguage());
076: if (c || (l && v)) {
077: buffer.append('_').append(locale.getCountry()); // This may just
078: // append '_'
079: }
080: if (v && (l || c)) {
081: buffer.append('_').append(locale.getVariant());
082: }
083: }
084: if (extension != null) {
085: buffer.append('.');
086: buffer.append(extension);
087: }
088: return buffer.toString();
089: }
090:
091: /** Map of Class to alias String */
092: private final Map/*<Class, String>*/classAliasMap = new WeakHashMap();
093:
094: /** Map of alias String to WeakReference(Class) */
095: private final Map/*<String, WeakReference<Class>>*/aliasClassMap = new HashMap();
096:
097: /** Map of shared resources states */
098: private final Map/*<String, Resource>*/resourceMap = new HashMap();
099:
100: /**
101: * Construct.
102: *
103: * @param application
104: * The application
105: */
106: SharedResources(Application application) {
107: }
108:
109: /**
110: * Adds a resource.
111: *
112: * @param scope
113: * Scope of resource
114: * @param name
115: * Logical name of resource
116: * @param locale
117: * The locale of the resource
118: * @param style
119: * The resource style (see {@link org.apache.wicket.Session})
120: * @param resource
121: * Resource to store
122: */
123: public final void add(final Class scope, final String name,
124: final Locale locale, final String style,
125: final Resource resource) {
126: // Store resource
127: final String key = resourceKey(scope, name, locale, style);
128: synchronized (resourceMap) {
129: Resource value = (Resource) resourceMap.get(key);
130: if (value == null) {
131: resourceMap.put(key, resource);
132: if (log.isDebugEnabled()) {
133: log.debug("added shared resource " + key);
134: }
135: }
136: }
137: }
138:
139: /**
140: * Adds a resource.
141: *
142: * @param name
143: * Logical name of resource
144: * @param locale
145: * The locale of the resource
146: * @param resource
147: * Resource to store
148: */
149: public final void add(final String name, final Locale locale,
150: final Resource resource) {
151: add(Application.class, name, locale, null, resource);
152: }
153:
154: /**
155: * Adds a resource.
156: *
157: * @param name
158: * Logical name of resource
159: * @param resource
160: * Resource to store
161: */
162: public final void add(final String name, final Resource resource) {
163: add(Application.class, name, null, null, resource);
164: }
165:
166: /**
167: * @param scope
168: * The resource's scope
169: * @param name
170: * Name of resource to get
171: * @param locale
172: * The locale of the resource
173: * @param style
174: * The resource style (see {@link org.apache.wicket.Session})
175: * @param exact
176: * If true then only return the resource that is registered for
177: * the given locale and style.
178: *
179: * @return The logical resource
180: */
181: public final Resource get(final Class scope, final String name,
182: final Locale locale, final String style, boolean exact) {
183: // 1. Look for fully qualified entry with locale and style
184: if (locale != null && style != null) {
185: final String resourceKey = resourceKey(scope, name, locale,
186: style);
187: final Resource resource = get(resourceKey);
188: if (resource != null) {
189: return resource;
190: }
191: if (exact) {
192: return null;
193: }
194: }
195:
196: // 2. Look for entry without style
197: if (locale != null) {
198: final String key = resourceKey(scope, name, locale, null);
199: final Resource resource = get(key);
200: if (resource != null) {
201: return resource;
202: }
203: if (exact) {
204: return null;
205: }
206: }
207:
208: // 3. Look for entry without locale
209: if (style != null) {
210: final String key = resourceKey(scope, name, null, style);
211: final Resource resource = get(key);
212: if (resource != null) {
213: return resource;
214: }
215: if (exact) {
216: return null;
217: }
218: }
219:
220: // 4. Look for base name with no locale or style
221: final String key = resourceKey(scope, name, null, null);
222: return get(key);
223: }
224:
225: /**
226: * THIS METHOD IS NOT PART OF THE WICKET PUBLIC API. DO NOT USE IT.
227: *
228: * @param key
229: * Shared resource key
230: * @return The resource
231: */
232: public final Resource get(final String key) {
233: synchronized (resourceMap) {
234: return (Resource) resourceMap.get(key);
235: }
236: }
237:
238: /**
239: * Sets an alias for a class so that a resource url can look like:
240: * resources/images/Image.jpg instead of
241: * resources/org.apache.wicket.resources.ResourceClass/Image.jpg
242: *
243: * @param clz
244: * The class that has to be aliased.
245: * @param alias
246: * The alias string.
247: */
248: public final void putClassAlias(Class clz, String alias) {
249: classAliasMap.put(clz, alias);
250: aliasClassMap.put(alias, new WeakReference(clz));
251: }
252:
253: /**
254: * Gets the class for a given resource alias.
255: *
256: * @param alias
257: * @return The class this is an alias for.
258: * @see #putClassAlias(Class, String)
259: */
260: public final Class getAliasClass(String alias) {
261: Object classRef = aliasClassMap.get(alias);
262: if (classRef == null) {
263: return null;
264: }
265: return (Class) ((WeakReference) classRef).get();
266: }
267:
268: /**
269: * Removes a shared resource.
270: *
271: * @param key
272: * Shared resource key
273: */
274: public final void remove(final String key) {
275: synchronized (resourceMap) {
276: resourceMap.remove(key);
277: }
278: }
279:
280: /**
281: * THIS METHOD IS NOT PART OF THE WICKET PUBLIC API. DO NOT CALL IT.
282: *
283: * @param scope
284: * The scope of the resource
285: * @param path
286: * The resource path
287: * @param locale
288: * The locale
289: * @param style
290: * The style (see {@link org.apache.wicket.Session})
291: * @return The localized path
292: */
293: public String resourceKey(final Class scope, final String path,
294: final Locale locale, final String style) {
295: String alias = (String) classAliasMap.get(scope);
296: if (alias == null) {
297: alias = scope.getName();
298: }
299: return alias + '/' + resourceKey(path, locale, style);
300: }
301: }
|