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.Map;
020:
021: import org.apache.wicket.request.target.resource.ResourceStreamRequestTarget;
022: import org.apache.wicket.util.resource.IResourceStream;
023: import org.apache.wicket.util.time.Time;
024: import org.apache.wicket.util.value.ValueMap;
025: import org.slf4j.Logger;
026: import org.slf4j.LoggerFactory;
027:
028: /**
029: * A Resource is something that implements IResourceListener and provides a
030: * getResourceStream() method which returns the raw IResourceStream to be
031: * rendered back to the client browser.
032: * <p>
033: * Resources themselves do not currently have URLs. Instead, they are referred
034: * to by components that have URLs.
035: * <p>
036: * Resources can be shared throughout an application by adding them to
037: * Application with addResource(Class scope, String name) or addResource(String
038: * name). A resource added in such a way is a named resource and is accessible
039: * throughout the application via Application.getResource(Class scope, String
040: * name) or Application.getResource(String name). The ResourceReference class
041: * enables easy access to such resources in a way that is light on clusters.
042: * <p>
043: * While resources can be shared between components, it is important to
044: * emphasize that components <i>cannot </i> be shared among containers. For
045: * example, you can create a button image resource with new
046: * DefaultButtonImageResource(...) and store that in the Application with
047: * addResource(). You can then assign that logical resource via
048: * ResourceReference to several ImageButton components. While the button image
049: * resource can be shared between components like this, the ImageButton
050: * components in this example are like all other components in Wicket and cannot
051: * be shared.
052: *
053: * @author Jonathan Locke
054: * @author Johan Compagner
055: * @author Gili Tzabari
056: * @author Igor Vaynberg
057: */
058: public abstract class Resource implements IResourceListener {
059: private static final long serialVersionUID = 1L;
060:
061: /** Logger */
062: private static final Logger log = LoggerFactory
063: .getLogger(Resource.class);
064:
065: /** True if this resource can be cached */
066: private boolean cacheable;
067:
068: /**
069: * ThreadLocal to keep any parameters associated with the request for this
070: * resource
071: */
072: private static final ThreadLocal parameters = new ThreadLocal();
073:
074: /**
075: * Constructor
076: */
077: protected Resource() {
078: // By default all resources are cacheable
079: cacheable = true;
080: }
081:
082: /**
083: * @return Gets the resource to render to the requester
084: */
085: public abstract IResourceStream getResourceStream();
086:
087: /**
088: * @return boolean True or False if this resource is cacheable
089: */
090: public final boolean isCacheable() {
091: return cacheable;
092: }
093:
094: /**
095: * THIS METHOD IS NOT PART OF THE WICKET PUBLIC API. DO NOT CALL IT.
096: *
097: * Called when a resource is requested.
098: */
099: public final void onResourceRequested() {
100: try {
101: // Get request cycle
102: final RequestCycle cycle = RequestCycle.get();
103:
104: // Fetch resource from subclass if necessary
105: IResourceStream resourceStream = init();
106:
107: // Get servlet response to use when responding with resource
108: final Response response = cycle.getResponse();
109:
110: // FIXME WICKET-385 Move HTTP caching features out of org.apache.wicket.Resource
111: if (isCacheable()) {
112: response.setLastModifiedTime(resourceStream
113: .lastModifiedTime());
114: } else {
115: response.setLastModifiedTime(Time.valueOf(-1));
116: }
117: configureResponse(response);
118:
119: cycle.setRequestTarget(new ResourceStreamRequestTarget(
120: resourceStream));
121: } finally {
122: // Really really really make sure parameters are cleared
123: parameters.set(null);
124: }
125: }
126:
127: /**
128: * Should this resource be cacheable, so will it set the last modified and
129: * the some cache headers in the response.
130: *
131: * @param cacheable
132: * boolean if the lastmodified and cache headers must be set.
133: * @return this
134: */
135: public final Resource setCacheable(boolean cacheable) {
136: this .cacheable = cacheable;
137: return this ;
138: }
139:
140: /**
141: * THIS METHOD IS NOT PART OF THE WICKET PUBLIC API. DO NOT USE IT!
142: *
143: * @param parameters
144: * Map of query parameters that paramterize this resource
145: */
146: public final void setParameters(final Map parameters) {
147: if (parameters == null) {
148: Resource.parameters.set(null);
149: } else {
150: Resource.parameters.set(new ValueMap(parameters));
151: }
152: }
153:
154: /**
155: * Allows implementations to do configure the response, like setting headers
156: * etc.
157: *
158: * @param response
159: * the respone
160: */
161: protected void configureResponse(final Response response) {
162: }
163:
164: /**
165: * @return Any query parameters associated with the request for this
166: * resource
167: */
168: protected ValueMap getParameters() {
169: if (parameters.get() == null) {
170: setParameters(RequestCycle.get().getRequest()
171: .getParameterMap());
172: }
173: return (ValueMap) parameters.get();
174: }
175:
176: /**
177: * Sets any loaded resource to null, thus forcing a reload on the next
178: * request.
179: */
180: protected void invalidate() {
181: }
182:
183: /**
184: * Set resource field by calling subclass
185: *
186: * @return The resource stream for the current request
187: */
188: private final IResourceStream init() {
189: IResourceStream stream = getResourceStream();
190:
191: if (stream == null) {
192: throw new WicketRuntimeException(
193: "Could not get resource stream");
194: }
195: return stream;
196: }
197: }
|