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.util.Locale;
020:
021: import org.apache.wicket.markup.html.PackageResource;
022: import org.apache.wicket.util.lang.Classes;
023: import org.apache.wicket.util.lang.Objects;
024:
025: /**
026: * ResourceReference is essentially a reference to an actual resource which is
027: * shared through the Application. A ResourceReference has a name and a scope
028: * (within which the name must be unique). It may also have a locale or style.
029: * The locale and/or style do not need to be set on a resource reference because
030: * those values will automatically be determined based on the context in which
031: * the resource is being used. For example, if a ResourceReference is attached
032: * to an Image component, when the locale for the page switches, the Image
033: * component will notice this and automatically change the locale for the
034: * referenced resource as appropriate. It's for this reason that you don't
035: * typically have to use the constructor overloads taking a Locale or style
036: * (these details are essentially internal and so the framework uses
037: * setLocale/setStyle internally so you don't have to worry about it).
038: * <p>
039: * Package resources (resources which can be pulled from the classpath) do not
040: * have to be pre-registered. For custom situations though, resources may be
041: * added to the Application when the Application is constructed using
042: * {@link Application#getSharedResources()} followed by
043: * {@link SharedResources#add(Class, String, Locale, String, Resource)},
044: * {@link SharedResources#add(String, Locale, Resource)}or
045: * {@link SharedResources#add(String, Resource)}.
046: * <p>
047: * If a component has its own shared resource which should not be added to the
048: * application construction logic in this way, it can lazy-initialize the
049: * resource by overriding the {@link #newResource()} method. In this method, the
050: * component should supply logic that creates the shared resource. By default
051: * the {@link #newResource()} method tries to resolve to a package resource.
052: *
053: * @author Jonathan Locke
054: */
055: public class ResourceReference implements IClusterable {
056: private static final long serialVersionUID = 2L;
057:
058: /** The locale of the resource */
059: protected Locale locale;
060:
061: /** The name of the resource */
062: private final String name;
063:
064: /** The actual resource */
065: private transient Resource resource;
066:
067: /** The scope of the named resource */
068: private final String scopeName;
069:
070: /** The style of the resource */
071: private String style;
072:
073: /**
074: * Constructs a ResourceReference with the given scope and name. The scope
075: * is used as a namespace and the scope together with the name must uniquely
076: * identify the reference.
077: *
078: * @param scope
079: * The scope of the name
080: * @param name
081: * The name of the resource
082: */
083: public ResourceReference(final Class scope, final String name) {
084: this (scope, name, null, null);
085: }
086:
087: /**
088: * Constructs a ResourceReference with the given scope and name. The scope
089: * is used as a namespace and the scope together with the name must uniquely
090: * identify the reference. This constructor takes in the locale and style
091: * arguments. The locale might be overruled if this resource resolves to a
092: * package resource.
093: *
094: * @param scope
095: * The scope of the name
096: * @param name
097: * The name of the resource
098: * @param locale
099: * The Locale from which the search for the PackageResource must
100: * start
101: * @param style
102: * The Style of the PackageResource
103: */
104: public ResourceReference(final Class scope, final String name,
105: Locale locale, String style) {
106: this .scopeName = scope.getName();
107: this .name = name;
108: this .locale = locale;
109: this .style = style;
110: }
111:
112: /**
113: * Contructs a resource reference with Application.class scope and the given
114: * name. All resource references constructed with this constructor must have
115: * unique names since they all have the same Application-wide scope that is
116: * the org.apache.wicket.Application.class
117: *
118: * @param name
119: * The name of the resource
120: */
121: public ResourceReference(final String name) {
122: this (Application.class, name);
123: }
124:
125: /**
126: * Binds this shared resource to the given application.
127: *
128: * @param application
129: * The application which holds the shared resource
130: */
131: public final void bind(final Application application) {
132: // Try to resolve resource
133: if (resource == null) {
134: SharedResources sharedResources = application
135: .getSharedResources();
136: // Try to get resource from Application repository
137: resource = sharedResources.get(getScope(), name, locale,
138: style, true);
139:
140: // Not available yet?
141: if (resource == null) {
142: // Create resource using lazy-init factory method
143: resource = newResource();
144: if (resource == null) {
145: // If lazy-init did not create resource with correct locale
146: // and style then we should default the resource
147: resource = sharedResources.get(getScope(), name,
148: locale, style, false);
149: if (resource == null) {
150: // still null? try to see whether it is a package
151: // resource that should
152: // be lazily loaded
153: PackageResource packageResource = PackageResource
154: .get(getScope(), name);
155: // will throw an exception if not found, so if we come
156: // here, it was found
157: sharedResources.add(name, packageResource);
158: }
159: }
160:
161: // Share through application
162: sharedResources.add(getScope(), name, locale, style,
163: resource);
164: }
165: }
166: }
167:
168: /**
169: * @see java.lang.Object#equals(java.lang.Object)
170: */
171: public boolean equals(Object obj) {
172: if (obj instanceof ResourceReference) {
173: ResourceReference that = (ResourceReference) obj;
174: return Objects.equal(this .getScope().getName(), that
175: .getScope().getName())
176: && Objects.equal(this .name, that.name)
177: && Objects.equal(this .locale, that.locale)
178: && Objects.equal(this .style, that.style);
179: }
180: return false;
181: }
182:
183: /**
184: * @return Returns the locale.
185: */
186: public final Locale getLocale() {
187: return locale;
188: }
189:
190: /**
191: * @return Name
192: */
193: public final String getName() {
194: return name;
195: }
196:
197: /**
198: * Gets the resource for this resource reference. If the ResourceReference
199: * has not yet been bound to the application via
200: * {@link ResourceReference#bind(Application)}this method may return null.
201: *
202: * @return The resource, or null if the ResourceReference has not yet been
203: * bound.
204: */
205: public final Resource getResource() {
206: return resource;
207: }
208:
209: /**
210: * @return Scope
211: */
212: public final Class getScope() {
213: return Classes.resolveClass(scopeName);
214: }
215:
216: /**
217: * @return the shared resource key for this resource reference.
218: */
219: public final String getSharedResourceKey() {
220: Application application = Application.get();
221: bind(application);
222: return application.getSharedResources().resourceKey(getScope(),
223: name, locale, style);
224: }
225:
226: /**
227: * @return Returns the style. (see {@link org.apache.wicket.Session})
228: */
229: public final String getStyle() {
230: return style;
231: }
232:
233: /**
234: * @see java.lang.Object#hashCode()
235: */
236: public int hashCode() {
237: int result = 17;
238: result = 37 * result
239: + (scopeName != null ? scopeName.hashCode() : 0);
240: result = 37 * result + (name != null ? name.hashCode() : 0);
241: result = 37 * result + (locale != null ? locale.hashCode() : 0);
242: result = 37 * result + (style != null ? style.hashCode() : 0);
243: return result;
244: }
245:
246: /**
247: * Sets any loaded resource to null, thus forcing a reload on the next
248: * request.
249: */
250: public final void invalidate() {
251: this .resource = null;
252: }
253:
254: /**
255: * @param locale
256: * The locale to set.
257: */
258: public final void setLocale(Locale locale) {
259: this .locale = locale;
260: invalidate();
261: }
262:
263: /**
264: * @param style
265: * The style to set (see {@link org.apache.wicket.Session}).
266: */
267: public final void setStyle(String style) {
268: this .style = style;
269: invalidate();
270: }
271:
272: /**
273: * @see java.lang.Object#toString()
274: */
275: public String toString() {
276: return "[ResourceReference name = " + name + ", scope = "
277: + scopeName + ", locale = " + locale + ", style = "
278: + style + "]";
279: }
280:
281: /**
282: * Factory method for lazy initialization of shared resources.
283: *
284: * @return The resource
285: */
286: protected Resource newResource() {
287: PackageResource packageResource = PackageResource.get(
288: getScope(), getName(), getLocale(), getStyle());
289: if (packageResource != null) {
290: locale = packageResource.getLocale();
291: } else {
292: throw new IllegalArgumentException(
293: "package resource [scope=" + getScope() + ",name="
294: + getName() + ",locale=" + getLocale()
295: + "style=" + getStyle() + "] not found");
296: }
297: return packageResource;
298: }
299: }
|