You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@wicket.apache.org by kn...@apache.org on 2007/08/23 01:27:47 UTC

svn commit: r568767 - in /wicket/trunk/jdk-1.4/wicket/src/main/java/org/apache/wicket: RequestCycle.java ResourceReference.java markup/html/PackageResource.java settings/IResourceSettings.java settings/Settings.java

Author: knopp
Date: Wed Aug 22 16:27:46 2007
New Revision: 568767

URL: http://svn.apache.org/viewvc?rev=568767&view=rev
Log:
Added option to encode last modified time into resource reference urls

Modified:
    wicket/trunk/jdk-1.4/wicket/src/main/java/org/apache/wicket/RequestCycle.java
    wicket/trunk/jdk-1.4/wicket/src/main/java/org/apache/wicket/ResourceReference.java
    wicket/trunk/jdk-1.4/wicket/src/main/java/org/apache/wicket/markup/html/PackageResource.java
    wicket/trunk/jdk-1.4/wicket/src/main/java/org/apache/wicket/settings/IResourceSettings.java
    wicket/trunk/jdk-1.4/wicket/src/main/java/org/apache/wicket/settings/Settings.java

Modified: wicket/trunk/jdk-1.4/wicket/src/main/java/org/apache/wicket/RequestCycle.java
URL: http://svn.apache.org/viewvc/wicket/trunk/jdk-1.4/wicket/src/main/java/org/apache/wicket/RequestCycle.java?rev=568767&r1=568766&r2=568767&view=diff
==============================================================================
--- wicket/trunk/jdk-1.4/wicket/src/main/java/org/apache/wicket/RequestCycle.java (original)
+++ wicket/trunk/jdk-1.4/wicket/src/main/java/org/apache/wicket/RequestCycle.java Wed Aug 22 16:27:46 2007
@@ -39,6 +39,7 @@
 import org.apache.wicket.request.target.component.listener.ListenerInterfaceRequestTarget;
 import org.apache.wicket.request.target.resource.SharedResourceRequestTarget;
 import org.apache.wicket.util.collections.ArrayListStack;
+import org.apache.wicket.util.time.Time;
 import org.apache.wicket.util.value.ValueMap;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -46,54 +47,49 @@
 
 /**
  * Represents the processing of a request. It is responsible for instructing the
- * {@link IRequestCycleProcessor request cycle processor} to execute the various
- * steps there are in the handling of a request (resolving the kind of work that
- * needs to be done, handling of events and generating a response), and it holds
- * the intended {@link IRequestTarget request target}, which is an abstraction
- * for e.g. the processing of a bookmarkable page.
+ * {@link IRequestCycleProcessor request cycle processor} to execute the various steps there are in
+ * the handling of a request (resolving the kind of work that needs to be done, handling of events
+ * and generating a response), and it holds the intended {@link IRequestTarget request target},
+ * which is an abstraction for e.g. the processing of a bookmarkable page.
  * <p>
- * The abstract urlFor() methods are implemented by subclasses of RequestCycle
- * and return encoded page URLs. The URL returned depends on the kind of page
- * being linked to. Pages broadly fall into two categories:
+ * The abstract urlFor() methods are implemented by subclasses of RequestCycle and return encoded
+ * page URLs. The URL returned depends on the kind of page being linked to. Pages broadly fall into
+ * two categories:
  * <p>
  * <table>
  * <tr>
  * <td valign = "top"><b>1. </b></td>
- * <td>A page that does not yet exist in a user Session may be encoded as a URL
- * that references the not-yet-created page by class name. A set of
- * PageParameters can also be encoded into the URL, and these parameters will be
- * passed to the page constructor if the page later needs to be instantiated.
+ * <td>A page that does not yet exist in a user Session may be encoded as a URL that references the
+ * not-yet-created page by class name. A set of PageParameters can also be encoded into the URL, and
+ * these parameters will be passed to the page constructor if the page later needs to be
+ * instantiated.
  * <p>
- * Any page of this type is bookmarkable, and a hint to that effect is given to
- * the user in the URL:
+ * Any page of this type is bookmarkable, and a hint to that effect is given to the user in the URL:
  * <p>
  * <ul>
  * /[Application]?bookmarkablePage=[classname]&[param]=[value] [...]
  * </ul>
  * <p>
- * Bookmarkable pages must either implement a constructor that takes a
- * PageParameters argument or a default constructor. If a Page has both
- * constructors the constuctor with the PageParameters argument will be used.
- * Links to bookmarkable pages are created by calling the urlFor(Class,
- * PageParameters) method, where Class is the page class and PageParameters are
- * the parameters to encode into the URL.
+ * Bookmarkable pages must either implement a constructor that takes a PageParameters argument or a
+ * default constructor. If a Page has both constructors the constuctor with the PageParameters
+ * argument will be used. Links to bookmarkable pages are created by calling the urlFor(Class,
+ * PageParameters) method, where Class is the page class and PageParameters are the parameters to
+ * encode into the URL.
  * <p>
  * </td>
  * </tr>
  * <tr>
  * <td valign = "top"><b>2. </b></td>
- * <td>Stateful pages (that have already been requested by a user) will be
- * present in the user's Session and can be referenced securely with a
- * session-relative number:
+ * <td>Stateful pages (that have already been requested by a user) will be present in the user's
+ * Session and can be referenced securely with a session-relative number:
  * <p>
  * <ul>
  * /[Application]?wicket:interface=[pageMapName]:[pageId]: ...
  * </ul>
  * <p>
- * Often, the reason to access an existing session page is due to some kind of
- * "postback" (either a link click or a form submit) from a page (possibly
- * accessed with the browser's back button or possibly not). A call to a
- * registered listener is dispatched like so:
+ * Often, the reason to access an existing session page is due to some kind of "postback" (either a
+ * link click or a form submit) from a page (possibly accessed with the browser's back button or
+ * possibly not). A call to a registered listener is dispatched like so:
  * <p>
  * <ul>
  * /[Application]?wicket:interface=[pageMapName]:[pageId]:[componentPath]:[version]:[interfaceName]
@@ -108,18 +104,15 @@
  * </tr>
  * </table>
  * <p>
- * URLs for stateful pages (those that already exist in the session map) are
- * created by calling the urlFor(Component, Class) method, where Component is
- * the component being linked to and Class is the interface on the component to
- * call.
+ * URLs for stateful pages (those that already exist in the session map) are created by calling the
+ * urlFor(Component, Class) method, where Component is the component being linked to and Class is
+ * the interface on the component to call.
  * <p>
- * For pages falling into the second category, listener interfaces cannot be
- * invoked unless they have first been registered via the static
- * registerSecureInterface() method. This method ensures basic security by
- * restricting the set of interfaces that outsiders can call via GET and POST
- * requests. Each listener interface has a single method which takes only a
- * RequestCycle parameter. Currently, the following classes register the
- * following kinds of listener interfaces:
+ * For pages falling into the second category, listener interfaces cannot be invoked unless they
+ * have first been registered via the static registerSecureInterface() method. This method ensures
+ * basic security by restricting the set of interfaces that outsiders can call via GET and POST
+ * requests. Each listener interface has a single method which takes only a RequestCycle parameter.
+ * Currently, the following classes register the following kinds of listener interfaces:
  * <p>
  * <table>
  * <tr>
@@ -149,15 +142,13 @@
  * </tr>
  * </table>
  * <p>
- * The redirectToInterceptPage() and continueToOriginalDestination() methods can
- * be used to temporarily redirect a user to some page. This is mainly intended
- * for use in signing in users who have bookmarked a page inside a site that
- * requires the user be authenticated before they can access the page. When it
- * is discovered that the user is not signed in, the user is redirected to the
- * sign-in page with redirectToInterceptPage(). When the user has signed in,
- * they are sent on their way with continueToOriginalDestination(). These
- * methods could also be useful in "interstitial" advertising or other kinds of
- * "intercepts".
+ * The redirectToInterceptPage() and continueToOriginalDestination() methods can be used to
+ * temporarily redirect a user to some page. This is mainly intended for use in signing in users who
+ * have bookmarked a page inside a site that requires the user be authenticated before they can
+ * access the page. When it is discovered that the user is not signed in, the user is redirected to
+ * the sign-in page with redirectToInterceptPage(). When the user has signed in, they are sent on
+ * their way with continueToOriginalDestination(). These methods could also be useful in
+ * "interstitial" advertising or other kinds of "intercepts".
  * <p>
  * 
  * @author Jonathan Locke
@@ -209,11 +200,10 @@
 	}
 
 	/**
-	 * Sets the request cycle for the calling thread. You typically DO NOT NEED
-	 * to call this method, as the request cycle is set to current for you in
-	 * the constructor. However, if you have a <a
-	 * href="http://issues.apache.org/jira/browse/WICKET-366">very special need</a>
-	 * to set it to something else, you can expose this method.
+	 * Sets the request cycle for the calling thread. You typically DO NOT NEED to call this method,
+	 * as the request cycle is set to current for you in the constructor. However, if you have a <a
+	 * href="http://issues.apache.org/jira/browse/WICKET-366">very special need</a> to set it to
+	 * something else, you can expose this method.
 	 * 
 	 * @param cycle
 	 *            The request cycle to set current
@@ -224,8 +214,8 @@
 	}
 
 	/**
-	 * True if the request cycle should automatically clear feedback messages
-	 * after processing. True by default.
+	 * True if the request cycle should automatically clear feedback messages after processing. True
+	 * by default.
 	 */
 	private boolean automaticallyClearFeedbackMessages = true;
 
@@ -236,8 +226,8 @@
 	private final Response originalResponse;
 
 	/**
-	 * True if request should be redirected to the resulting page instead of
-	 * just rendering it back to the user.
+	 * True if request should be redirected to the resulting page instead of just rendering it back
+	 * to the user.
 	 */
 	private boolean redirect;
 
@@ -245,8 +235,8 @@
 	private transient final ArrayListStack requestTargets = new ArrayListStack(3);
 
 	/**
-	 * Any page parameters. Only set when the request is resolving and the
-	 * parameters are passed into a page.
+	 * Any page parameters. Only set when the request is resolving and the parameters are passed
+	 * into a page.
 	 */
 	private PageParameters pageParameters;
 
@@ -269,8 +259,7 @@
 	protected Response response;
 
 	/**
-	 * Constructor. This instance will be set as the current one for this
-	 * thread.
+	 * Constructor. This instance will be set as the current one for this thread.
 	 * 
 	 * @param application
 	 *            The application
@@ -285,8 +274,8 @@
 		this.application = application;
 		this.request = request;
 		this.response = response;
-		this.originalResponse = response;
-		this.processor = safeGetRequestProcessor();
+		originalResponse = response;
+		processor = safeGetRequestProcessor();
 
 		// Set this RequestCycle into ThreadLocal variable
 		current.set(this);
@@ -304,9 +293,8 @@
 
 	/**
 	 * Gets the new agent info object for this session. This method calls
-	 * {@link Session#getClientInfo()}, which may or may not cache the client
-	 * info object and typically calls {@link #newClientInfo()} when no client
-	 * info object was cached.
+	 * {@link Session#getClientInfo()}, which may or may not cache the client info object and
+	 * typically calls {@link #newClientInfo()} when no client info object was cached.
 	 * 
 	 * @return the agent info object based on this request
 	 */
@@ -316,28 +304,26 @@
 	}
 
 	/**
-	 * Get the orignal respone the request was create with. Access may be
-	 * necessary with the response has temporarily being replaced but your
-	 * components requires access to lets say the cookie methods of a
-	 * WebResponse.
+	 * Get the orignal respone the request was create with. Access may be necessary with the
+	 * response has temporarily being replaced but your components requires access to lets say the
+	 * cookie methods of a WebResponse.
 	 * 
 	 * @return The original response object.
 	 */
 	public final Response getOriginalResponse()
 	{
-		return this.originalResponse;
+		return originalResponse;
 	}
 
 	/**
-	 * Any set page parameters. Typically only available when a request to a
-	 * bookmarkable page with a {@link Page#Page(PageParameters)} constructor
-	 * was made.
+	 * Any set page parameters. Typically only available when a request to a bookmarkable page with
+	 * a {@link Page#Page(PageParameters)} constructor was made.
 	 * 
 	 * @return the page parameters or null
 	 */
 	public final PageParameters getPageParameters()
 	{
-		return this.pageParameters;
+		return pageParameters;
 	}
 
 	/**
@@ -389,8 +375,8 @@
 	}
 
 	/**
-	 * Gets the page that is to be rendered for this request in case the last
-	 * set request target is of type {@link PageRequestTarget}.
+	 * Gets the page that is to be rendered for this request in case the last set request target is
+	 * of type {@link PageRequestTarget}.
 	 * 
 	 * @return the page or null
 	 */
@@ -409,9 +395,8 @@
 	}
 
 	/**
-	 * Gets the page class that is to be instantiated and rendered for this
-	 * request in case the last set request target is of type
-	 * {@link BookmarkablePageRequestTarget}.
+	 * Gets the page class that is to be instantiated and rendered for this request in case the last
+	 * set request target is of type {@link BookmarkablePageRequestTarget}.
 	 * 
 	 * @return the page class or null
 	 */
@@ -458,8 +443,8 @@
 	}
 
 	/**
-	 * Template method that is called when a runtime exception is thrown, just
-	 * before the actual handling of the runtime exception. This is called by
+	 * Template method that is called when a runtime exception is thrown, just before the actual
+	 * handling of the runtime exception. This is called by
 	 * {@link AbstractRequestCycleProcessor#respond(RuntimeException, RequestCycle)}.
 	 * 
 	 * @param page
@@ -476,8 +461,8 @@
 	/**
 	 * THIS METHOD IS NOT PART OF THE WICKET PUBLIC API. DO NOT CALL IT.
 	 * <p>
-	 * Redirects browser to the given page. Don't use this method directly, but
-	 * use {@link #setResponsePage(Page)} instead.
+	 * Redirects browser to the given page. Don't use this method directly, but use
+	 * {@link #setResponsePage(Page)} instead.
 	 * 
 	 * @param page
 	 *            The page to redirect to
@@ -547,12 +532,10 @@
 	}
 
 	/**
-	 * Permit clients like testers to examine feedback messages after
-	 * processing.
+	 * Permit clients like testers to examine feedback messages after processing.
 	 * 
 	 * @param automaticallyClearFeedbackMessages
-	 *            True to automatically detach request cycle at end of
-	 *            processing
+	 *            True to automatically detach request cycle at end of processing
 	 */
 	public void setAutomaticallyClearFeedbackMessages(boolean automaticallyClearFeedbackMessages)
 	{
@@ -565,8 +548,8 @@
 	 * Sets whether the page for this request should be redirected.
 	 * 
 	 * @param redirect
-	 *            True if the page for this request cycle should be redirected
-	 *            to rather than directly rendered.
+	 *            True if the page for this request cycle should be redirected to rather than
+	 *            directly rendered.
 	 */
 	public final void setRedirect(final boolean redirect)
 	{
@@ -638,8 +621,8 @@
 	}
 
 	/**
-	 * Convenience method that sets page class as the response. This will
-	 * generate a redirect to the page with a bookmarkable url
+	 * Convenience method that sets page class as the response. This will generate a redirect to the
+	 * page with a bookmarkable url
 	 * 
 	 * @param pageClass
 	 *            The page class to render as a response
@@ -650,14 +633,12 @@
 	}
 
 	/**
-	 * Sets the page class with optionally the page parameters as the render
-	 * target of this request.
+	 * Sets the page class with optionally the page parameters as the render target of this request.
 	 * 
 	 * @param pageClass
 	 *            The page class to render as a response
 	 * @param pageParameters
-	 *            The page parameters that gets appended to the bookmarkable
-	 *            url,
+	 *            The page parameters that gets appended to the bookmarkable url,
 	 */
 	public final void setResponsePage(final Class pageClass, final PageParameters pageParameters)
 	{
@@ -682,15 +663,14 @@
 	 */
 	public String toString()
 	{
-		return "[RequestCycle" + "@" + Integer.toHexString(hashCode()) + " thread="
-				+ Thread.currentThread().getName() + "]";
+		return "[RequestCycle" + "@" + Integer.toHexString(hashCode()) + " thread=" +
+				Thread.currentThread().getName() + "]";
 	}
 
 	/**
-	 * Returns a bookmarkable URL that references a given page class using a
-	 * given set of page parameters. Since the URL which is returned contains
-	 * all information necessary to instantiate and render the page, it can be
-	 * stored in a user's browser as a stable bookmark.
+	 * Returns a bookmarkable URL that references a given page class using a given set of page
+	 * parameters. Since the URL which is returned contains all information necessary to instantiate
+	 * and render the page, it can be stored in a user's browser as a stable bookmark.
 	 * 
 	 * @param pageClass
 	 *            Class of page
@@ -704,10 +684,10 @@
 	}
 
 	/**
-	 * Returns a URL that references a given interface on a given behaviour of a
-	 * component. When the URL is requested from the server at a later time, the
-	 * interface on the behaviour will be called. A URL returned by this method
-	 * will not be stable across sessions and cannot be bookmarked by a user.
+	 * Returns a URL that references a given interface on a given behaviour of a component. When the
+	 * URL is requested from the server at a later time, the interface on the behaviour will be
+	 * called. A URL returned by this method will not be stable across sessions and cannot be
+	 * bookmarked by a user.
 	 * 
 	 * @param component
 	 *            The component to reference
@@ -715,8 +695,7 @@
 	 *            The behaviour to reference
 	 * @param listener
 	 *            The listener interface on the component
-	 * @return A URL that encodes a page, component, behaviour and interface to
-	 *         call
+	 * @return A URL that encodes a page, component, behaviour and interface to call
 	 */
 	public final CharSequence urlFor(final Component component, final IBehavior behaviour,
 			final RequestListenerInterface listener)
@@ -724,8 +703,8 @@
 		int index = component.getBehaviors().indexOf(behaviour);
 		if (index == -1)
 		{
-			throw new IllegalArgumentException("Behavior " + this
-					+ " was not registered with this component: " + component.toString());
+			throw new IllegalArgumentException("Behavior " + this +
+					" was not registered with this component: " + component.toString());
 		}
 		RequestParameters params = new RequestParameters();
 		params.setBehaviorId(String.valueOf(index));
@@ -749,10 +728,9 @@
 	}
 
 	/**
-	 * Returns a URL that references a given interface on a component. When the
-	 * URL is requested from the server at a later time, the interface will be
-	 * called. A URL returned by this method will not be stable across sessions
-	 * and cannot be bookmarked by a user.
+	 * Returns a URL that references a given interface on a component. When the URL is requested
+	 * from the server at a later time, the interface will be called. A URL returned by this method
+	 * will not be stable across sessions and cannot be bookmarked by a user.
 	 * 
 	 * @param component
 	 *            The component to reference
@@ -766,11 +744,11 @@
 		// Get Page holding component and mark it as stateful.
 		final Page page = component.getPage();
 		final IRequestTarget target;
-		if (listener != IRedirectListener.INTERFACE && component.isStateless()
-				&& page.isBookmarkable())
+		if (listener != IRedirectListener.INTERFACE && component.isStateless() &&
+				page.isBookmarkable())
 		{
-			target = new BookmarkableListenerInterfaceRequestTarget(page.getPageMapName(),
-					page.getClass(), new PageParameters(), component, listener);
+			target = new BookmarkableListenerInterfaceRequestTarget(page.getPageMapName(), page
+					.getClass(), new PageParameters(), component, listener);
 		}
 		else
 		{
@@ -792,14 +770,12 @@
 	}
 
 	/**
-	 * Returns a bookmarkable URL that references a given page class using a
-	 * given set of page parameters. Since the URL which is returned contains
-	 * all information necessary to instantiate and render the page, it can be
-	 * stored in a user's browser as a stable bookmark.
+	 * Returns a bookmarkable URL that references a given page class using a given set of page
+	 * parameters. Since the URL which is returned contains all information necessary to instantiate
+	 * and render the page, it can be stored in a user's browser as a stable bookmark.
 	 * 
 	 * @param pageMap
-	 *            Pagemap to use. If null is passed the default page map will be
-	 *            used
+	 *            Pagemap to use. If null is passed the default page map will be used
 	 * @param pageClass
 	 *            Class of page
 	 * @param parameters
@@ -831,10 +807,9 @@
 	}
 
 	/**
-	 * Returns a URL that references the given page. It also
-	 * {@link Session#touch(Page) touches} the page in the session so that it is
-	 * put in the front of the page stack. Use this method only if you plan to
-	 * use it the next request.
+	 * Returns a URL that references the given page. It also {@link Session#touch(Page) touches} the
+	 * page in the session so that it is put in the front of the page stack. Use this method only if
+	 * you plan to use it the next request.
 	 * 
 	 * @param page
 	 *            The page
@@ -848,8 +823,7 @@
 	}
 
 	/**
-	 * Returns a URL that references a shared resource through the provided
-	 * resource reference.
+	 * Returns a URL that references a shared resource through the provided resource reference.
 	 * 
 	 * @param resourceReference
 	 *            The resource reference where a url must be generated for.
@@ -861,8 +835,7 @@
 	}
 
 	/**
-	 * Returns a URL that references a shared resource through the provided
-	 * resource reference.
+	 * Returns a URL that references a shared resource through the provided resource reference.
 	 * 
 	 * @param resourceReference
 	 *            The resource reference where a url must be generated for.
@@ -874,6 +847,19 @@
 	{
 		RequestParameters requestParameters = new RequestParameters();
 		requestParameters.setResourceKey(resourceReference.getSharedResourceKey());
+		if (getApplication().getResourceSettings().getAddLastModifiedTimeToResourceReferenceUrl())
+		{
+			Time time = resourceReference.lastModifiedTime();
+			if (time != null)
+			{
+				if (parameters == null)
+				{
+					parameters = new ValueMap();
+					parameters.put("wicket:lm", new Long(time.getMilliseconds()));
+				}
+			}
+		}
+
 		requestParameters.setParameters(parameters);
 		CharSequence url = getProcessor().getRequestCodingStrategy().encode(this,
 				new SharedResourceRequestTarget(requestParameters));
@@ -881,16 +867,16 @@
 	}
 
 	/**
-	 * Checks whether no processing has been done yet and throws an exception
-	 * when a client tries to reuse this instance.
+	 * Checks whether no processing has been done yet and throws an exception when a client tries to
+	 * reuse this instance.
 	 */
 	private void checkReuse()
 	{
 		if (currentStep != NOT_STARTED)
 		{
 			throw new WicketRuntimeException(
-					"RequestCycles are non-reusable objects. This instance (" + this
-							+ ") already executed");
+					"RequestCycles are non-reusable objects. This instance (" + this +
+							") already executed");
 		}
 	}
 
@@ -958,11 +944,11 @@
 			}
 			catch (RuntimeException re)
 			{
-				log.error("there was an error detaching the request from the session " + session
-						+ ".", re);
+				log.error("there was an error detaching the request from the session " + session +
+						".", re);
 			}
 		}
-		
+
 		if (getResponse() instanceof BufferedWebResponse)
 		{
 			try
@@ -983,7 +969,7 @@
 		{
 			log.error("Exception occurred during onEndRequest", e);
 		}
-		
+
 		try
 		{
 			getApplication().getSessionStore().onEndRequest(getRequest());
@@ -992,7 +978,7 @@
 		{
 			log.error("Exception occurred during onEndRequest of the SessionStore", e);
 		}
-		
+
 		// Release thread local resources
 		try
 		{
@@ -1023,8 +1009,8 @@
 	}
 
 	/**
-	 * Call the event processing and and respond methods on the request
-	 * processor and apply synchronization if needed.
+	 * Call the event processing and and respond methods on the request processor and apply
+	 * synchronization if needed.
 	 */
 	private final void processEventsAndRespond()
 	{
@@ -1039,8 +1025,8 @@
 	}
 
 	/**
-	 * Call the event processing and and respond methods on the request
-	 * processor and apply synchronization if needed.
+	 * Call the event processing and and respond methods on the request processor and apply
+	 * synchronization if needed.
 	 */
 	private final void respond()
 	{
@@ -1048,8 +1034,7 @@
 	}
 
 	/**
-	 * Safe version of {@link #getProcessor()} that throws an exception when the
-	 * processor is null.
+	 * Safe version of {@link #getProcessor()} that throws an exception when the processor is null.
 	 * 
 	 * @return the request processor
 	 */
@@ -1169,8 +1154,8 @@
 				// code.
 				if (totalSteps >= maxSteps)
 				{
-					throw new IllegalStateException("Request processing executed " + maxSteps
-							+ " steps, which means it is probably in an infinite loop.");
+					throw new IllegalStateException("Request processing executed " + maxSteps +
+							" steps, which means it is probably in an infinite loop.");
 				}
 				try
 				{
@@ -1200,10 +1185,9 @@
 	}
 
 	/**
-	 * Releases the current thread local related resources. The threadlocal of
-	 * this request cycle is reset. If we are in a 'redirect' state, we do not
-	 * want to lose our messages as - e.g. when handling a form - there's a fat
-	 * chance we are coming back for the rendering of it.
+	 * Releases the current thread local related resources. The threadlocal of this request cycle is
+	 * reset. If we are in a 'redirect' state, we do not want to lose our messages as - e.g. when
+	 * handling a form - there's a fat chance we are coming back for the rendering of it.
 	 */
 	private final void threadDetach()
 	{
@@ -1226,8 +1210,8 @@
 	}
 
 	/**
-	 * Possibly set the page parameters. Only set when the request is resolving
-	 * and the parameters are passed into a page.
+	 * Possibly set the page parameters. Only set when the request is resolving and the parameters
+	 * are passed into a page.
 	 * 
 	 * @param parameters
 	 *            the parameters to set
@@ -1236,15 +1220,14 @@
 	{
 		if (currentStep == RESOLVE_TARGET)
 		{
-			this.pageParameters = parameters;
+			pageParameters = parameters;
 		}
 	}
 
 	/**
-	 * Called when an unrecoverable runtime exception during request cycle
-	 * handling occured, which will result in displaying a user facing error
-	 * page. Clients can override this method in case they want to customize
-	 * logging. NOT called for
+	 * Called when an unrecoverable runtime exception during request cycle handling occured, which
+	 * will result in displaying a user facing error page. Clients can override this method in case
+	 * they want to customize logging. NOT called for
 	 * {@link PageExpiredException page expired exceptions}.
 	 * 
 	 * @param e
@@ -1256,10 +1239,9 @@
 	}
 
 	/**
-	 * Creates a new agent info object based on this request. Typically, this
-	 * method is called once by the session and the returned object will be
-	 * cached in the session after that call; we can expect the client to stay
-	 * the same for the whole session, and implementations of
+	 * Creates a new agent info object based on this request. Typically, this method is called once
+	 * by the session and the returned object will be cached in the session after that call; we can
+	 * expect the client to stay the same for the whole session, and implementations of
 	 * {@link #newClientInfo()} might be relatively expensive.
 	 * 
 	 * @return the agent info object based on this request
@@ -1279,17 +1261,16 @@
 	protected void onEndRequest()
 	{
 	}
-	
+
 	/**
 	 * MetaDataEntry array.
 	 */
 	private MetaDataEntry[] metaData;
 
 	/**
-	 * Sets the metadata for this request cycle using the given key. If the metadata
-	 * object is not of the correct type for the metadata key, an
-	 * IllegalArgumentException will be thrown. For information on creating
-	 * MetaDataKeys, see {@link MetaDataKey}.
+	 * Sets the metadata for this request cycle using the given key. If the metadata object is not
+	 * of the correct type for the metadata key, an IllegalArgumentException will be thrown. For
+	 * information on creating MetaDataKeys, see {@link MetaDataKey}.
 	 * 
 	 * @param key
 	 *            The singleton key for the metadata
@@ -1302,7 +1283,7 @@
 	{
 		metaData = key.set(metaData, object);
 	}
-	
+
 	/**
 	 * Gets metadata for this request cycle using the given key.
 	 * 

Modified: wicket/trunk/jdk-1.4/wicket/src/main/java/org/apache/wicket/ResourceReference.java
URL: http://svn.apache.org/viewvc/wicket/trunk/jdk-1.4/wicket/src/main/java/org/apache/wicket/ResourceReference.java?rev=568767&r1=568766&r2=568767&view=diff
==============================================================================
--- wicket/trunk/jdk-1.4/wicket/src/main/java/org/apache/wicket/ResourceReference.java (original)
+++ wicket/trunk/jdk-1.4/wicket/src/main/java/org/apache/wicket/ResourceReference.java Wed Aug 22 16:27:46 2007
@@ -21,35 +21,34 @@
 import org.apache.wicket.markup.html.PackageResource;
 import org.apache.wicket.util.lang.Classes;
 import org.apache.wicket.util.lang.Objects;
+import org.apache.wicket.util.time.Time;
+import org.apache.wicket.util.watch.IModifiable;
 
 
 /**
- * ResourceReference is essentially a reference to an actual resource which is
- * shared through the Application. A ResourceReference has a name and a scope
- * (within which the name must be unique). It may also have a locale or style.
- * The locale and/or style do not need to be set on a resource reference because
- * those values will automatically be determined based on the context in which
- * the resource is being used. For example, if a ResourceReference is attached
- * to an Image component, when the locale for the page switches, the Image
- * component will notice this and automatically change the locale for the
- * referenced resource as appropriate. It's for this reason that you don't
- * typically have to use the constructor overloads taking a Locale or style
- * (these details are essentially internal and so the framework uses
- * setLocale/setStyle internally so you don't have to worry about it).
+ * ResourceReference is essentially a reference to an actual resource which is shared through the
+ * Application. A ResourceReference has a name and a scope (within which the name must be unique).
+ * It may also have a locale or style. The locale and/or style do not need to be set on a resource
+ * reference because those values will automatically be determined based on the context in which the
+ * resource is being used. For example, if a ResourceReference is attached to an Image component,
+ * when the locale for the page switches, the Image component will notice this and automatically
+ * change the locale for the referenced resource as appropriate. It's for this reason that you don't
+ * typically have to use the constructor overloads taking a Locale or style (these details are
+ * essentially internal and so the framework uses setLocale/setStyle internally so you don't have to
+ * worry about it).
  * <p>
- * Package resources (resources which can be pulled from the classpath) do not
- * have to be pre-registered. For custom situations though, resources may be
- * added to the Application when the Application is constructed using
- * {@link Application#getSharedResources()} followed by
+ * Package resources (resources which can be pulled from the classpath) do not have to be
+ * pre-registered. For custom situations though, resources may be added to the Application when the
+ * Application is constructed using {@link Application#getSharedResources()} followed by
  * {@link SharedResources#add(Class, String, Locale, String, Resource)},
  * {@link SharedResources#add(String, Locale, Resource)}or
  * {@link SharedResources#add(String, Resource)}.
  * <p>
- * If a component has its own shared resource which should not be added to the
- * application construction logic in this way, it can lazy-initialize the
- * resource by overriding the {@link #newResource()} method. In this method, the
- * component should supply logic that creates the shared resource. By default
- * the {@link #newResource()} method tries to resolve to a package resource.
+ * If a component has its own shared resource which should not be added to the application
+ * construction logic in this way, it can lazy-initialize the resource by overriding the
+ * {@link #newResource()} method. In this method, the component should supply logic that creates the
+ * shared resource. By default the {@link #newResource()} method tries to resolve to a package
+ * resource.
  * 
  * @author Jonathan Locke
  */
@@ -65,7 +64,7 @@
 
 	/** The actual resource */
 	private transient Resource resource;
-	
+
 	/** The scope of the named resource */
 	private final String scopeName;
 
@@ -73,9 +72,8 @@
 	private String style;
 
 	/**
-	 * Constructs a ResourceReference with the given scope and name. The scope
-	 * is used as a namespace and the scope together with the name must uniquely
-	 * identify the reference.
+	 * Constructs a ResourceReference with the given scope and name. The scope is used as a
+	 * namespace and the scope together with the name must uniquely identify the reference.
 	 * 
 	 * @param scope
 	 *            The scope of the name
@@ -88,35 +86,32 @@
 	}
 
 	/**
-	 * Constructs a ResourceReference with the given scope and name. The scope
-	 * is used as a namespace and the scope together with the name must uniquely
-	 * identify the reference. This constructor takes in the locale and style
-	 * arguments. The locale might be overruled if this resource resolves to a
-	 * package resource.
+	 * Constructs a ResourceReference with the given scope and name. The scope is used as a
+	 * namespace and the scope together with the name must uniquely identify the reference. This
+	 * constructor takes in the locale and style arguments. The locale might be overruled if this
+	 * resource resolves to a package resource.
 	 * 
 	 * @param scope
 	 *            The scope of the name
 	 * @param name
 	 *            The name of the resource
 	 * @param locale
-	 *            The Locale from which the search for the PackageResource must
-	 *            start
+	 *            The Locale from which the search for the PackageResource must start
 	 * @param style
 	 *            The Style of the PackageResource
 	 */
 	public ResourceReference(final Class scope, final String name, Locale locale, String style)
 	{
-		this.scopeName = scope.getName();
+		scopeName = scope.getName();
 		this.name = name;
 		this.locale = locale;
 		this.style = style;
 	}
 
 	/**
-	 * Contructs a resource reference with Application.class scope and the given
-	 * name. All resource references constructed with this constructor must have
-	 * unique names since they all have the same Application-wide scope that is
-	 * the org.apache.wicket.Application.class
+	 * Contructs a resource reference with Application.class scope and the given name. All resource
+	 * references constructed with this constructor must have unique names since they all have the
+	 * same Application-wide scope that is the org.apache.wicket.Application.class
 	 * 
 	 * @param name
 	 *            The name of the resource
@@ -177,9 +172,9 @@
 		if (obj instanceof ResourceReference)
 		{
 			ResourceReference that = (ResourceReference)obj;
-			return Objects.equal(this.getScope().getName(), that.getScope().getName()) && Objects.equal(this.name, that.name)
-					&& Objects.equal(this.locale, that.locale)
-					&& Objects.equal(this.style, that.style);
+			return Objects.equal(getScope().getName(), that.getScope().getName()) &&
+					Objects.equal(name, that.name) && Objects.equal(locale, that.locale) &&
+					Objects.equal(style, that.style);
 		}
 		return false;
 	}
@@ -201,12 +196,11 @@
 	}
 
 	/**
-	 * Gets the resource for this resource reference. If the ResourceReference
-	 * has not yet been bound to the application via
-	 * {@link ResourceReference#bind(Application)}this method may return null.
+	 * Gets the resource for this resource reference. If the ResourceReference has not yet been
+	 * bound to the application via {@link ResourceReference#bind(Application)}this method may
+	 * return null.
 	 * 
-	 * @return The resource, or null if the ResourceReference has not yet been
-	 *         bound.
+	 * @return The resource, or null if the ResourceReference has not yet been bound.
 	 */
 	public final Resource getResource()
 	{
@@ -253,12 +247,11 @@
 	}
 
 	/**
-	 * Sets any loaded resource to null, thus forcing a reload on the next
-	 * request.
+	 * Sets any loaded resource to null, thus forcing a reload on the next request.
 	 */
 	public final void invalidate()
 	{
-		this.resource = null;
+		resource = null;
 	}
 
 	/**
@@ -286,8 +279,8 @@
 	 */
 	public String toString()
 	{
-		return "[ResourceReference name = " + name + ", scope = " + scopeName + ", locale = " + locale
-				+ ", style = " + style + "]";
+		return "[ResourceReference name = " + name + ", scope = " + scopeName + ", locale = " +
+				locale + ", style = " + style + "]";
 	}
 
 	/**
@@ -305,9 +298,27 @@
 		}
 		else
 		{
-			throw new IllegalArgumentException("package resource [scope=" + getScope() + ",name="
-					+ getName() + ",locale=" + getLocale() + "style=" + getStyle() + "] not found");
+			throw new IllegalArgumentException("package resource [scope=" + getScope() + ",name=" +
+					getName() + ",locale=" + getLocale() + "style=" + getStyle() + "] not found");
 		}
 		return packageResource;
+	}
+
+	/**
+	 * Returns the last modified time of resource referenced by this reference.
+	 * 
+	 * @return last modified time or null if the time couldn't have been determined
+	 */
+	public Time lastModifiedTime()
+	{
+		Resource resource = getResource();
+		if (resource instanceof IModifiable)
+		{
+			return ((IModifiable)resource).lastModifiedTime();
+		}
+		else
+		{
+			return null;
+		}
 	}
 }

Modified: wicket/trunk/jdk-1.4/wicket/src/main/java/org/apache/wicket/markup/html/PackageResource.java
URL: http://svn.apache.org/viewvc/wicket/trunk/jdk-1.4/wicket/src/main/java/org/apache/wicket/markup/html/PackageResource.java?rev=568767&r1=568766&r2=568767&view=diff
==============================================================================
--- wicket/trunk/jdk-1.4/wicket/src/main/java/org/apache/wicket/markup/html/PackageResource.java (original)
+++ wicket/trunk/jdk-1.4/wicket/src/main/java/org/apache/wicket/markup/html/PackageResource.java Wed Aug 22 16:27:46 2007
@@ -45,6 +45,8 @@
 import org.apache.wicket.util.lang.Packages;
 import org.apache.wicket.util.resource.IResourceStream;
 import org.apache.wicket.util.string.Strings;
+import org.apache.wicket.util.time.Time;
+import org.apache.wicket.util.watch.IModifiable;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -58,14 +60,14 @@
  * PackageResource IMG_UNKNOWN = PackageResource.get(EditPage.class, &quot;questionmark.gif&quot;);
  * </pre>
  * 
- * where the static resource references image 'questionmark.gif' from the the
- * package that EditPage is in to get a package resource.
+ * where the static resource references image 'questionmark.gif' from the the package that EditPage
+ * is in to get a package resource.
  * </p>
  * 
  * @author Jonathan Locke
  * @author Eelco Hillenius
  */
-public class PackageResource extends WebResource
+public class PackageResource extends WebResource implements IModifiable
 {
 	/**
 	 * Exception thrown when the creation of a package resource is not allowed.
@@ -86,20 +88,16 @@
 	}
 
 	/**
-	 * common extension pattern for css files; matches all files with extension
-	 * 'css'.
+	 * common extension pattern for css files; matches all files with extension 'css'.
 	 * 
-	 * @deprecated Will be removed in 2.0; contribute resources one by one
-	 *             instead
+	 * @deprecated Will be removed in 2.0; contribute resources one by one instead
 	 */
 	public static final Pattern EXTENSION_CSS = Pattern.compile(".*\\.css");
 
 	/**
-	 * common extension pattern for javascript files; matches all files with
-	 * extension 'js'.
+	 * common extension pattern for javascript files; matches all files with extension 'js'.
 	 * 
-	 * @deprecated Will be removed in 2.0; contribute resources one by one
-	 *             instead
+	 * @deprecated Will be removed in 2.0; contribute resources one by one instead
 	 */
 	public static final Pattern EXTENSION_JS = Pattern.compile(".*\\.js");
 
@@ -109,61 +107,56 @@
 	private static final long serialVersionUID = 1L;
 
 	/**
-	 * Binds the resources that match the provided pattern to the given
-	 * application object. Will create any resources if not already in the
-	 * shared resources of the application object.
+	 * Binds the resources that match the provided pattern to the given application object. Will
+	 * create any resources if not already in the shared resources of the application object.
 	 * 
 	 * @param application
 	 *            The application to bind to.
 	 * @param scope
 	 *            The scope of the resource.
 	 * @param pattern
-	 *            A regular expression to match against the contents of the
-	 *            package of the provided scope class (eg &quot;.*\\.js&quot;
-	 *            will add all the files with extension &quot;js&quot; from that
-	 *            package).
+	 *            A regular expression to match against the contents of the package of the provided
+	 *            scope class (eg &quot;.*\\.js&quot; will add all the files with extension
+	 *            &quot;js&quot; from that package).
 	 * 
 	 * @deprecated Since Wicket 1.2.1 this method is effectively a no-op.
-	 *             {@link PackageResource package resources} are automatically
-	 *             tried and bound as shared resources so that they don't have
-	 *             to be pre-registered anymore. Will be removed in 2.0
+	 *             {@link PackageResource package resources} are automatically tried and bound as
+	 *             shared resources so that they don't have to be pre-registered anymore. Will be
+	 *             removed in 2.0
 	 */
 	public static void bind(Application application, Class scope, Pattern pattern)
 	{
 	}
 
 	/**
-	 * Binds the resources that match the provided pattern to the given
-	 * application object. Will create any resources if not already in the
-	 * shared resources of the application object and does that recursively when
-	 * the recurse parameter is true, or just for the scoped package if that
-	 * parameter is false
+	 * Binds the resources that match the provided pattern to the given application object. Will
+	 * create any resources if not already in the shared resources of the application object and
+	 * does that recursively when the recurse parameter is true, or just for the scoped package if
+	 * that parameter is false
 	 * 
 	 * @param application
 	 *            The application to bind to.
 	 * @param scope
 	 *            The scope of the resource.
 	 * @param pattern
-	 *            A regular expression to match against the contents of the
-	 *            package of the provided scope class (eg &quot;.*\\.js&quot;
-	 *            will add all the files with extension &quot;js&quot; from that
-	 *            package).
+	 *            A regular expression to match against the contents of the package of the provided
+	 *            scope class (eg &quot;.*\\.js&quot; will add all the files with extension
+	 *            &quot;js&quot; from that package).
 	 * @param recurse
 	 *            Whether this method should recurse into sub packages
 	 * 
 	 * @deprecated Since Wicket 1.2.1 this method is effectively a no-op.
-	 *             {@link PackageResource package resources} are automatically
-	 *             tried and bound as shared resources so that they don't have
-	 *             to be pre-registered anymore. Will be removed in 2.0
+	 *             {@link PackageResource package resources} are automatically tried and bound as
+	 *             shared resources so that they don't have to be pre-registered anymore. Will be
+	 *             removed in 2.0
 	 */
 	public static void bind(Application application, Class scope, Pattern pattern, boolean recurse)
 	{
 	}
 
 	/**
-	 * Binds a resource to the given application object. Will create the
-	 * resource if not already in the shared resources of the application
-	 * object.
+	 * Binds a resource to the given application object. Will create the resource if not already in
+	 * the shared resources of the application object.
 	 * 
 	 * @param application
 	 *            The application to bind to.
@@ -171,8 +164,7 @@
 	 *            The scope of the resource.
 	 * @param name
 	 *            The name of the resource (like &quot;myfile.js&quot;)
-	 * @throw IllegalArgumentException when the requested package resource was
-	 *        not found
+	 * @throw IllegalArgumentException when the requested package resource was not found
 	 */
 	public static void bind(Application application, Class scope, String name)
 	{
@@ -180,9 +172,8 @@
 	}
 
 	/**
-	 * Binds a resource to the given application object. Will create the
-	 * resource if not already in the shared resources of the application
-	 * object.
+	 * Binds a resource to the given application object. Will create the resource if not already in
+	 * the shared resources of the application object.
 	 * 
 	 * @param application
 	 *            The application to bind to.
@@ -192,8 +183,7 @@
 	 *            The name of the resource (like &quot;myfile.js&quot;)
 	 * @param locale
 	 *            The locale of the resource.
-	 * @throw IllegalArgumentException when the requested package resource was
-	 *        not found
+	 * @throw IllegalArgumentException when the requested package resource was not found
 	 */
 	public static void bind(Application application, Class scope, String name, Locale locale)
 	{
@@ -201,9 +191,8 @@
 	}
 
 	/**
-	 * Binds a resource to the given application object. Will create the
-	 * resource if not already in the shared resources of the application
-	 * object.
+	 * Binds a resource to the given application object. Will create the resource if not already in
+	 * the shared resources of the application object.
 	 * 
 	 * @param application
 	 *            The application to bind to.
@@ -215,8 +204,7 @@
 	 *            The locale of the resource.
 	 * @param style
 	 *            The style of the resource.
-	 * @throw IllegalArgumentException when the requested package resource was
-	 *        not found
+	 * @throw IllegalArgumentException when the requested package resource was not found
 	 */
 	public static void bind(Application application, Class scope, String name, Locale locale,
 			String style)
@@ -236,8 +224,8 @@
 		}
 		else
 		{
-			throw new IllegalArgumentException("no package resource was found for scope " + scope
-					+ ", name " + name + ", locale " + locale + ", style " + style);
+			throw new IllegalArgumentException("no package resource was found for scope " + scope +
+					", name " + name + ", locale " + locale + ", style " + style);
 		}
 	}
 
@@ -245,9 +233,9 @@
 	 * Gets whether a resource for a given set of criteria exists.
 	 * 
 	 * @param scope
-	 *            This argument will be used to get the class loader for loading
-	 *            the package resource, and to determine what package it is in.
-	 *            Typically this is the class in which you call this method
+	 *            This argument will be used to get the class loader for loading the package
+	 *            resource, and to determine what package it is in. Typically this is the class in
+	 *            which you call this method
 	 * @param path
 	 *            The path to the resource
 	 * @param locale
@@ -265,20 +253,18 @@
 	}
 
 	/**
-	 * Gets non-localized resources for a given set of criteria. Multiple
-	 * resource can be loaded for the same criteria if they match the pattern.
-	 * If no resources were found, this method returns null.
+	 * Gets non-localized resources for a given set of criteria. Multiple resource can be loaded for
+	 * the same criteria if they match the pattern. If no resources were found, this method returns
+	 * null.
 	 * 
 	 * @param scope
-	 *            This argument will be used to get the class loader for loading
-	 *            the package resource, and to determine what package it is in.
-	 *            Typically this is the calling class/ the class in which you
-	 *            call this method
+	 *            This argument will be used to get the class loader for loading the package
+	 *            resource, and to determine what package it is in. Typically this is the calling
+	 *            class/ the class in which you call this method
 	 * @param pattern
 	 *            Regexp pattern to match resources
 	 * @return The resources, never null but may be empty
-	 * @deprecated Will be removed in 2.0; contribute resources one by one
-	 *             instead
+	 * @deprecated Will be removed in 2.0; contribute resources one by one instead
 	 */
 	public static PackageResource[] get(Class scope, Pattern pattern)
 	{
@@ -286,22 +272,20 @@
 	}
 
 	/**
-	 * Gets non-localized resources for a given set of criteria. Multiple
-	 * resource can be loaded for the same criteria if they match the pattern.
-	 * If no resources were found, this method returns null.
+	 * Gets non-localized resources for a given set of criteria. Multiple resource can be loaded for
+	 * the same criteria if they match the pattern. If no resources were found, this method returns
+	 * null.
 	 * 
 	 * @param scope
-	 *            This argument will be used to get the class loader for loading
-	 *            the package resource, and to determine what package it is in.
-	 *            Typically this is the calling class/ the class in which you
-	 *            call this method
+	 *            This argument will be used to get the class loader for loading the package
+	 *            resource, and to determine what package it is in. Typically this is the calling
+	 *            class/ the class in which you call this method
 	 * @param pattern
 	 *            Regexp pattern to match resources
 	 * @param recurse
 	 *            Whether this method should recurse into sub packages
 	 * @return The resources, never null but may be empty
-	 * @deprecated Will be removed in 2.0; contribute resources one by one
-	 *             instead
+	 * @deprecated Will be removed in 2.0; contribute resources one by one instead
 	 */
 	public static PackageResource[] get(Class scope, Pattern pattern, boolean recurse)
 	{
@@ -368,8 +352,8 @@
 					}
 					if (!basedir.isDirectory())
 					{
-						throw new IllegalStateException("unable to read resources from directory "
-								+ basedir);
+						throw new IllegalStateException("unable to read resources from directory " +
+								basedir);
 					}
 				}
 			}
@@ -383,14 +367,13 @@
 	}
 
 	/**
-	 * Gets a non-localized resource for a given set of criteria. Only one
-	 * resource will be loaded for the same criteria.
+	 * Gets a non-localized resource for a given set of criteria. Only one resource will be loaded
+	 * for the same criteria.
 	 * 
 	 * @param scope
-	 *            This argument will be used to get the class loader for loading
-	 *            the package resource, and to determine what package it is in.
-	 *            Typically this is the calling class/ the class in which you
-	 *            call this method
+	 *            This argument will be used to get the class loader for loading the package
+	 *            resource, and to determine what package it is in. Typically this is the calling
+	 *            class/ the class in which you call this method
 	 * @param path
 	 *            The path to the resource
 	 * @return The resource
@@ -401,13 +384,13 @@
 	}
 
 	/**
-	 * Gets the resource for a given set of criteria. Only one resource will be
-	 * loaded for the same criteria.
+	 * Gets the resource for a given set of criteria. Only one resource will be loaded for the same
+	 * criteria.
 	 * 
 	 * @param scope
-	 *            This argument will be used to get the class loader for loading
-	 *            the package resource, and to determine what package it is in.
-	 *            Typically this is the class in which you call this method
+	 *            This argument will be used to get the class loader for loading the package
+	 *            resource, and to determine what package it is in. Typically this is the class in
+	 *            which you call this method
 	 * @param path
 	 *            The path to the resource
 	 * @param locale
@@ -470,8 +453,8 @@
 	 * Hidden constructor.
 	 * 
 	 * @param scope
-	 *            This argument will be used to get the class loader for loading
-	 *            the package resource, and to determine what package it is in
+	 *            This argument will be used to get the class loader for loading the package
+	 *            resource, and to determine what package it is in
 	 * @param path
 	 *            The path to the resource
 	 * @param locale
@@ -483,17 +466,17 @@
 			final String style)
 	{
 		// Convert resource path to absolute path relative to base package
-		this.absolutePath = Packages.absolutePath(scope, path);
+		absolutePath = Packages.absolutePath(scope, path);
 
 		IPackageResourceGuard guard = Application.get().getResourceSettings()
 				.getPackageResourceGuard();
 		if (!guard.accept(scope, path))
 		{
-			throw new PackageResourceBlockedException("package resource " + absolutePath
-					+ " may not be accessed");
+			throw new PackageResourceBlockedException("package resource " + absolutePath +
+					" may not be accessed");
 		}
 
-		this.scopeName = scope.getName();
+		scopeName = scope.getName();
 		this.path = path;
 		this.locale = locale;
 		this.style = style;
@@ -551,8 +534,8 @@
 		// Check that resource was found
 		if (resourceStream == null)
 		{
-			String msg = "Unable to find package resource [path = " + absolutePath + ", style = "
-					+ style + ", locale = " + locale + "]";
+			String msg = "Unable to find package resource [path = " + absolutePath + ", style = " +
+					style + ", locale = " + locale + "]";
 			log.warn(msg);
 			if (RequestCycle.get() instanceof WebRequestCycle)
 			{
@@ -563,13 +546,20 @@
 				throw new AbortException();
 			}
 		}
-		this.locale = resourceStream.getLocale();
+
+		locale = resourceStream.getLocale();
+
+		if (resourceStream != null)
+		{
+			lastModifiedTime = resourceStream.lastModifiedTime();
+			lastModifiedTimeUpdate = System.currentTimeMillis();
+		}
+
 		return resourceStream;
 	}
 
 	/**
-	 * Gets the scoping class, used for class loading and to determine the
-	 * package.
+	 * Gets the scoping class, used for class loading and to determine the package.
 	 * 
 	 * @return the scoping class
 	 */
@@ -586,5 +576,25 @@
 	public final String getStyle()
 	{
 		return style;
+	}
+
+	private transient Time lastModifiedTime = null;
+	private transient long lastModifiedTimeUpdate = 0;
+
+	/**
+	 * Returns the last modified time of resource
+	 * 
+	 * @return last modified time or nulll if the time can not be determined
+	 */
+	public Time lastModifiedTime()
+	{
+		if (lastModifiedTimeUpdate == 0 ||
+				lastModifiedTimeUpdate < System.currentTimeMillis() - 5 * (1000 * 60))
+		{
+			lastModifiedTime = getResourceStream().lastModifiedTime();
+			lastModifiedTimeUpdate = System.currentTimeMillis();
+		}
+		return lastModifiedTime;
+
 	}
 }

Modified: wicket/trunk/jdk-1.4/wicket/src/main/java/org/apache/wicket/settings/IResourceSettings.java
URL: http://svn.apache.org/viewvc/wicket/trunk/jdk-1.4/wicket/src/main/java/org/apache/wicket/settings/IResourceSettings.java?rev=568767&r1=568766&r2=568767&view=diff
==============================================================================
--- wicket/trunk/jdk-1.4/wicket/src/main/java/org/apache/wicket/settings/IResourceSettings.java (original)
+++ wicket/trunk/jdk-1.4/wicket/src/main/java/org/apache/wicket/settings/IResourceSettings.java Wed Aug 22 16:27:46 2007
@@ -35,44 +35,37 @@
 /**
  * Interface for resource related settings
  * <p>
- * <i>resourcePollFrequency </i> (defaults to no polling frequency) - Frequency
- * at which resources should be polled for changes.
+ * <i>resourcePollFrequency </i> (defaults to no polling frequency) - Frequency at which resources
+ * should be polled for changes.
  * <p>
- * <i>resourceFinder </i> (classpath) - Set this to alter the search path for
- * resources.
+ * <i>resourceFinder </i> (classpath) - Set this to alter the search path for resources.
  * <p>
- * <i>useDefaultOnMissingResource </i> (defaults to true) - Set to true to
- * return a default value if available when a required string resource is not
- * found. If set to false then the throwExceptionOnMissingResource flag is used
- * to determine how to behave. If no default is available then this is the same
- * as if this flag were false
- * <p>
- * <i>A ResourceStreamLocator </i>- An Application's ResourceStreamLocator is
- * used to find resources such as images or markup files. You can supply your
- * own ResourceStreamLocator if your prefer to store your application's
- * resources in a non-standard location (such as a different filesystem
- * location, a particular JAR file or even a database) by overriding the
- * getResourceLocator() method.
- * <p>
- * <i>Resource Factories </i>- Resource factories can be used to create
- * resources dynamically from specially formatted HTML tag attribute values. For
- * more details, see {@link IResourceFactory},
- * {@link org.apache.wicket.markup.html.image.resource.DefaultButtonImageResourceFactory}
- * and especially
- * {@link org.apache.wicket.markup.html.image.resource.LocalizedImageResource}.
- * <p>
- * <i>A Localizer </i> The getLocalizer() method returns an object encapsulating
- * all of the functionality required to access localized resources. For many
- * localization problems, even this will not be required, as there are
- * convenience methods available to all components:
+ * <i>useDefaultOnMissingResource </i> (defaults to true) - Set to true to return a default value if
+ * available when a required string resource is not found. If set to false then the
+ * throwExceptionOnMissingResource flag is used to determine how to behave. If no default is
+ * available then this is the same as if this flag were false
+ * <p>
+ * <i>A ResourceStreamLocator </i>- An Application's ResourceStreamLocator is used to find resources
+ * such as images or markup files. You can supply your own ResourceStreamLocator if your prefer to
+ * store your application's resources in a non-standard location (such as a different filesystem
+ * location, a particular JAR file or even a database) by overriding the getResourceLocator()
+ * method.
+ * <p>
+ * <i>Resource Factories </i>- Resource factories can be used to create resources dynamically from
+ * specially formatted HTML tag attribute values. For more details, see {@link IResourceFactory},
+ * {@link org.apache.wicket.markup.html.image.resource.DefaultButtonImageResourceFactory} and
+ * especially {@link org.apache.wicket.markup.html.image.resource.LocalizedImageResource}.
+ * <p>
+ * <i>A Localizer </i> The getLocalizer() method returns an object encapsulating all of the
+ * functionality required to access localized resources. For many localization problems, even this
+ * will not be required, as there are convenience methods available to all components:
  * {@link org.apache.wicket.Component#getString(String key)} and
  * {@link org.apache.wicket.Component#getString(String key, IModel model)}.
  * <p>
- * <i>stringResourceLoaders </i>- A chain of <code>IStringResourceLoader</code>
- * instances that are searched in order to obtain string resources used during
- * localization. By default the chain is set up to first search for resources
- * against a particular component (e.g. page etc.) and then against the
- * application.
+ * <i>stringResourceLoaders </i>- A chain of <code>IStringResourceLoader</code> instances that are
+ * searched in order to obtain string resources used during localization. By default the chain is
+ * set up to first search for resources against a particular component (e.g. page etc.) and then
+ * against the application.
  * </p>
  * 
  * @author Igor Vaynberg (ivaynberg)
@@ -80,8 +73,8 @@
 public interface IResourceSettings
 {
 	/**
-	 * Adds a resource factory to the list of factories to consult when
-	 * generating resources automatically
+	 * Adds a resource factory to the list of factories to consult when generating resources
+	 * automatically
 	 * 
 	 * @param name
 	 *            The name to give to the factory
@@ -91,10 +84,9 @@
 	void addResourceFactory(final String name, final IResourceFactory resourceFactory);
 
 	/**
-	 * Convenience method that sets the resource search path to a single folder.
-	 * use when searching for resources. By default, the resources are located
-	 * on the classpath. If you want to configure other, additional, search
-	 * paths, you can use this method
+	 * Convenience method that sets the resource search path to a single folder. use when searching
+	 * for resources. By default, the resources are located on the classpath. If you want to
+	 * configure other, additional, search paths, you can use this method
 	 * 
 	 * @param resourceFolder
 	 *            The resourceFolder to set
@@ -102,9 +94,9 @@
 	void addResourceFolder(final String resourceFolder);
 
 	/**
-	 * Add a string resource loader to the chain of loaders. If this is the
-	 * first call to this method since the creation of the application settings
-	 * then the existing chain is cleared before the new loader is added.
+	 * Add a string resource loader to the chain of loaders. If this is the first call to this
+	 * method since the creation of the application settings then the existing chain is cleared
+	 * before the new loader is added.
 	 * 
 	 * @param loader
 	 *            The loader to be added
@@ -112,8 +104,8 @@
 	void addStringResourceLoader(final IStringResourceLoader loader);
 
 	/**
-	 * Whether to disable gzip compression for resources. You need this on SAP,
-	 * which gzips things twice.
+	 * Whether to disable gzip compression for resources. You need this on SAP, which gzips things
+	 * twice.
 	 * 
 	 * @return True if we should disable gzip compression
 	 * @since 1.3.0
@@ -124,8 +116,7 @@
 	 * Get the application's localizer.
 	 * 
 	 * @see IResourceSettings#addStringResourceLoader(org.apache.wicket.resource.loader.IStringResourceLoader)
-	 *      for means of extending the way Wicket resolves keys to localized
-	 *      messages.
+	 *      for means of extending the way Wicket resolves keys to localized messages.
 	 * 
 	 * @return The application wide localizer instance
 	 */
@@ -173,11 +164,10 @@
 
 	/**
 	 * @param start
-	 *            boolean if the resource watcher should be started if not
-	 *            already started.
+	 *            boolean if the resource watcher should be started if not already started.
 	 * 
-	 * @return Resource watcher with polling frequency determined by setting, or
-	 *         null if no polling frequency has been set.
+	 * @return Resource watcher with polling frequency determined by setting, or null if no polling
+	 *         frequency has been set.
 	 */
 	ModificationWatcher getResourceWatcher(boolean start);
 
@@ -194,14 +184,13 @@
 	boolean getThrowExceptionOnMissingResource();
 
 	/**
-	 * @return Whether to use a default value (if available) when a missing
-	 *         resource is requested
+	 * @return Whether to use a default value (if available) when a missing resource is requested
 	 */
 	boolean getUseDefaultOnMissingResource();
 
 	/**
-	 * Sets whether to disable gzip compression for resources. You need to set
-	 * this on some SAP versions, which gzip things twice.
+	 * Sets whether to disable gzip compression for resources. You need to set this on some SAP
+	 * versions, which gzip things twice.
 	 * 
 	 * @param disableGZipCompression
 	 * @since 1.3.0
@@ -232,9 +221,9 @@
 	void setPropertiesFactory(IPropertiesFactory factory);
 
 	/**
-	 * Sets the finder to use when searching for resources. By default, the
-	 * resources are located on the classpath. If you want to configure other,
-	 * additional, search paths, you can use this method.
+	 * Sets the finder to use when searching for resources. By default, the resources are located on
+	 * the classpath. If you want to configure other, additional, search paths, you can use this
+	 * method.
 	 * 
 	 * @param resourceFinder
 	 *            The resourceFinder to set
@@ -242,10 +231,9 @@
 	void setResourceFinder(final IResourceFinder resourceFinder);
 
 	/**
-	 * Sets the resource polling frequency. This is the duration of time between
-	 * checks of resource modification times. If a resource, such as an HTML
-	 * file, has changed, it will be reloaded. Default is for no resource
-	 * polling to occur.
+	 * Sets the resource polling frequency. This is the duration of time between checks of resource
+	 * modification times. If a resource, such as an HTML file, has changed, it will be reloaded.
+	 * Default is for no resource polling to occur.
 	 * 
 	 * @param resourcePollFrequency
 	 *            Frequency at which to poll resources
@@ -270,22 +258,36 @@
 
 	/**
 	 * @param useDefaultOnMissingResource
-	 *            Whether to use a default value (if available) when a missing
-	 *            resource is requested
+	 *            Whether to use a default value (if available) when a missing resource is requested
 	 */
 	void setUseDefaultOnMissingResource(final boolean useDefaultOnMissingResource);
 
 	/**
-	 * Sets whether the whitespace characters and comments should be stripped
-	 * for resources served through {@link JavascriptPackageResource}
+	 * Sets whether the whitespace characters and comments should be stripped for resources served
+	 * through {@link JavascriptPackageResource}
 	 * 
 	 * @param value
 	 */
 	void setStripJavascriptCommentsAndWhitespace(boolean value);
 
 	/**
-	 * @return whether the comments and whitespace characters will be stripped
-	 *         from resources served through {@link JavascriptPackageResource}
+	 * @return whether the comments and whitespace characters will be stripped from resources served
+	 *         through {@link JavascriptPackageResource}
 	 */
 	boolean getStripJavascriptCommentsAndWhitespace();
+
+	/**
+	 * Sets whether Wicket should add last modified time as a parameter to resource reference URL
+	 * (can help with browsers too aggressively caching certain resources).
+	 * 
+	 * @param value
+	 */
+	public void setAddLastModifiedTimeToResourceReferenceUrl(boolean value);
+
+	/**
+	 * Returns whether Wicket should add last modified time as resource reference URL parameter.
+	 * 
+	 * @return
+	 */
+	public boolean getAddLastModifiedTimeToResourceReferenceUrl();
 }

Modified: wicket/trunk/jdk-1.4/wicket/src/main/java/org/apache/wicket/settings/Settings.java
URL: http://svn.apache.org/viewvc/wicket/trunk/jdk-1.4/wicket/src/main/java/org/apache/wicket/settings/Settings.java?rev=568767&r1=568766&r2=568767&view=diff
==============================================================================
--- wicket/trunk/jdk-1.4/wicket/src/main/java/org/apache/wicket/settings/Settings.java (original)
+++ wicket/trunk/jdk-1.4/wicket/src/main/java/org/apache/wicket/settings/Settings.java Wed Aug 22 16:27:46 2007
@@ -307,6 +307,8 @@
 	 */
 	private boolean outputMarkupContainerClassName = false;
 
+	private boolean addLastModifiedTimeToResourceReferenceUrl = false;
+
 	/**
 	 * Create the application settings, carrying out any necessary initialisations.
 	 * 
@@ -1324,5 +1326,15 @@
 	public void setLinePreciseReportingOnNewComponentEnabled(boolean enable)
 	{
 		linePreciseReportingOnNewComponentEnabled = enable;
+	}
+
+	public void setAddLastModifiedTimeToResourceReferenceUrl(boolean value)
+	{
+		addLastModifiedTimeToResourceReferenceUrl = value;
+	}
+
+	public boolean getAddLastModifiedTimeToResourceReferenceUrl()
+	{
+		return addLastModifiedTimeToResourceReferenceUrl;
 	}
 }