You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@wicket.apache.org by jr...@apache.org on 2010/11/11 03:12:02 UTC

svn commit: r1033801 - in /wicket/trunk/wicket/src/main/java/org/apache/wicket/resource: ./ aggregation/ dependencies/ filtering/

Author: jrthomerson
Date: Thu Nov 11 02:12:01 2010
New Revision: 1033801

URL: http://svn.apache.org/viewvc?rev=1033801&view=rev
Log:
add several implementations of IHeaderResponse that can be used with IHeaderResponseDecorator to build up various kinds of decoration for your header response.  Most of these are the core of the functionality, meant to be built on and extended as needed for your use cases

Added:
    wicket/trunk/wicket/src/main/java/org/apache/wicket/resource/ResourceUtil.java
    wicket/trunk/wicket/src/main/java/org/apache/wicket/resource/aggregation/
    wicket/trunk/wicket/src/main/java/org/apache/wicket/resource/aggregation/AbstractDependencyRespectingResourceAggregatingHeaderResponse.java
    wicket/trunk/wicket/src/main/java/org/apache/wicket/resource/aggregation/AbstractResourceAggregatingHeaderResponse.java
    wicket/trunk/wicket/src/main/java/org/apache/wicket/resource/aggregation/ResourceReferenceAndStringData.java
    wicket/trunk/wicket/src/main/java/org/apache/wicket/resource/aggregation/ResourceReferenceCollection.java
    wicket/trunk/wicket/src/main/java/org/apache/wicket/resource/dependencies/
    wicket/trunk/wicket/src/main/java/org/apache/wicket/resource/dependencies/AbstractResourceDependentResourceReference.java
    wicket/trunk/wicket/src/main/java/org/apache/wicket/resource/dependencies/IResourceReferenceDependencyConfigurationService.java
    wicket/trunk/wicket/src/main/java/org/apache/wicket/resource/dependencies/ResourceDependentResourceReference.java
    wicket/trunk/wicket/src/main/java/org/apache/wicket/resource/dependencies/ResourceReferenceDependencyInjectingHeaderResponse.java
    wicket/trunk/wicket/src/main/java/org/apache/wicket/resource/filtering/
    wicket/trunk/wicket/src/main/java/org/apache/wicket/resource/filtering/AbstractHeaderResponseFilter.java
    wicket/trunk/wicket/src/main/java/org/apache/wicket/resource/filtering/CssAcceptingHeaderResponseFilter.java
    wicket/trunk/wicket/src/main/java/org/apache/wicket/resource/filtering/HeaderResponseContainerFilteringHeaderResponse.java
    wicket/trunk/wicket/src/main/java/org/apache/wicket/resource/filtering/HeaderResponseFilteredResponseContainer.java
    wicket/trunk/wicket/src/main/java/org/apache/wicket/resource/filtering/JavascriptAcceptingHeaderResponseFilter.java
    wicket/trunk/wicket/src/main/java/org/apache/wicket/resource/filtering/JavascriptFilteredIntoFooterHeaderResponse.java
    wicket/trunk/wicket/src/main/java/org/apache/wicket/resource/filtering/OppositeHeaderResponseFilter.java

Added: wicket/trunk/wicket/src/main/java/org/apache/wicket/resource/ResourceUtil.java
URL: http://svn.apache.org/viewvc/wicket/trunk/wicket/src/main/java/org/apache/wicket/resource/ResourceUtil.java?rev=1033801&view=auto
==============================================================================
--- wicket/trunk/wicket/src/main/java/org/apache/wicket/resource/ResourceUtil.java (added)
+++ wicket/trunk/wicket/src/main/java/org/apache/wicket/resource/ResourceUtil.java Thu Nov 11 02:12:01 2010
@@ -0,0 +1,75 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.wicket.resource;
+
+import org.apache.wicket.ResourceReference;
+import org.apache.wicket.markup.html.IHeaderResponse;
+import org.apache.wicket.util.string.Strings;
+
+/**
+ * Utilities for resources.
+ * 
+ * @author Jeremy Thomerson
+ */
+public class ResourceUtil
+{
+
+	private ResourceUtil()
+	{
+		// no-op
+	}
+
+	/**
+	 * Helper that calls the proper IHeaderResponse.render*Reference method based on the input.
+	 * 
+	 * @param resp
+	 *            the response to call render*Reference methods on
+	 * @param ref
+	 *            the reference to render
+	 * @param css
+	 *            true if this is a css reference
+	 * @param string
+	 *            the string argument to pass to those methods that accept it (js = id / css =
+	 *            media)
+	 */
+	public static void renderTo(IHeaderResponse resp, ResourceReference ref, boolean css,
+		String string)
+	{
+		if (css)
+		{
+			if (Strings.isEmpty(string))
+			{
+				resp.renderCSSReference(ref);
+			}
+			else
+			{
+				resp.renderCSSReference(ref, string);
+			}
+		}
+		else
+		{
+			if (Strings.isEmpty(string))
+			{
+				resp.renderJavascriptReference(ref);
+			}
+			else
+			{
+				resp.renderJavascriptReference(ref, string);
+			}
+		}
+	}
+}

Added: wicket/trunk/wicket/src/main/java/org/apache/wicket/resource/aggregation/AbstractDependencyRespectingResourceAggregatingHeaderResponse.java
URL: http://svn.apache.org/viewvc/wicket/trunk/wicket/src/main/java/org/apache/wicket/resource/aggregation/AbstractDependencyRespectingResourceAggregatingHeaderResponse.java?rev=1033801&view=auto
==============================================================================
--- wicket/trunk/wicket/src/main/java/org/apache/wicket/resource/aggregation/AbstractDependencyRespectingResourceAggregatingHeaderResponse.java (added)
+++ wicket/trunk/wicket/src/main/java/org/apache/wicket/resource/aggregation/AbstractDependencyRespectingResourceAggregatingHeaderResponse.java Thu Nov 11 02:12:01 2010
@@ -0,0 +1,89 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.wicket.resource.aggregation;
+
+import java.util.Set;
+
+import org.apache.wicket.ResourceReference;
+import org.apache.wicket.markup.html.IHeaderResponse;
+import org.apache.wicket.resource.dependencies.AbstractResourceDependentResourceReference;
+import org.apache.wicket.resource.dependencies.AbstractResourceDependentResourceReference.ResourceType;
+
+
+/**
+ * An implementation of AbstractResourceAggregatingHeaderResponse that renders references in the
+ * correct order if they are {@link AbstractResourceDependentResourceReference} references, ensuring
+ * that dependencies are rendered in the proper order before their parent (even if they do not
+ * appear in the same group as the parent of the depdencies).
+ * 
+ * @author Jeremy Thomerson
+ * @param <R>
+ *            the type of ResourceReferenceCollection returned by
+ *            {@link #newResourceReferenceCollection()} and passed to all the methods that take a
+ *            ResourceReferenceCollection. You will typically just use ResourceReferenceCollection
+ *            for this param, unless you are returning a specific type of
+ *            ResourceReferenceCollection from your subclass.
+ * @param <K>
+ *            the class of the key that you will create from
+ *            {@link #newGroupingKey(ResourceReferenceAndStringData)}
+ */
+public abstract class AbstractDependencyRespectingResourceAggregatingHeaderResponse<R extends ResourceReferenceCollection, K>
+	extends AbstractResourceAggregatingHeaderResponse<R, K>
+{
+
+	/**
+	 * Construct.
+	 * 
+	 * @param real
+	 *            the header response we decorate
+	 */
+	public AbstractDependencyRespectingResourceAggregatingHeaderResponse(IHeaderResponse real)
+	{
+		super(real);
+	}
+
+	@Override
+	protected void renderCollection(Set<ResourceReferenceAndStringData> alreadyRendered, K key,
+		R coll)
+	{
+		for (ResourceReferenceAndStringData data : coll)
+		{
+			ResourceReference ref = data.getReference();
+			if (ref instanceof AbstractResourceDependentResourceReference)
+			{
+				AbstractResourceDependentResourceReference parent = (AbstractResourceDependentResourceReference)ref;
+				R childColl = newResourceReferenceCollection();
+				for (AbstractResourceDependentResourceReference child : parent.getDependentResourceReferences())
+				{
+					childColl.add(toData(child));
+				}
+				// render the group of dependencies before the parent
+				renderCollection(alreadyRendered, key, childColl);
+			}
+			// now render the parent since the dependencies are rendered
+			renderIfNotAlreadyRendered(alreadyRendered, data);
+		}
+	}
+
+	private static ResourceReferenceAndStringData toData(
+		AbstractResourceDependentResourceReference child)
+	{
+		boolean css = ResourceType.CSS.equals(child.getResourceType());
+		String string = css ? child.getMedia() : child.getUniqueId();
+		return new ResourceReferenceAndStringData(child, string, css);
+	}
+}

Added: wicket/trunk/wicket/src/main/java/org/apache/wicket/resource/aggregation/AbstractResourceAggregatingHeaderResponse.java
URL: http://svn.apache.org/viewvc/wicket/trunk/wicket/src/main/java/org/apache/wicket/resource/aggregation/AbstractResourceAggregatingHeaderResponse.java?rev=1033801&view=auto
==============================================================================
--- wicket/trunk/wicket/src/main/java/org/apache/wicket/resource/aggregation/AbstractResourceAggregatingHeaderResponse.java (added)
+++ wicket/trunk/wicket/src/main/java/org/apache/wicket/resource/aggregation/AbstractResourceAggregatingHeaderResponse.java Thu Nov 11 02:12:01 2010
@@ -0,0 +1,291 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.wicket.resource.aggregation;
+
+import java.util.ArrayList;
+import java.util.Comparator;
+import java.util.LinkedHashSet;
+import java.util.List;
+import java.util.Map.Entry;
+import java.util.Set;
+import java.util.SortedMap;
+import java.util.TreeMap;
+
+import org.apache.wicket.Resource;
+import org.apache.wicket.ResourceReference;
+import org.apache.wicket.markup.html.DecoratingHeaderResponse;
+import org.apache.wicket.markup.html.IHeaderResponse;
+import org.apache.wicket.resource.ResourceUtil;
+
+/**
+ * A header response that can be used to aggregate resources (primarily resource references) into
+ * groups that can be rendered after the entire hierarchy of IHeaderContributors have been
+ * traversed. A subclass of this could use that group to render a single URL to some aggregating
+ * servlet (for example) that could cut down on the number of HTTP requests the client must make.
+ * 
+ * Resource references are aggregated according to the key that your subclass creates in the
+ * {@link #newGroupingKey(ResourceReferenceAndStringData)}. This key is used in a Map, so it needs
+ * to properly implement hashCode and equals.
+ * 
+ * If your key does not implement Comparable&lt;KeyClass&gt;, you need to also return a Comparator
+ * for it from the {@link #getGroupingKeyComparator()} method.
+ * 
+ * @author Jeremy Thomerson
+ * @param <R>
+ *            the type of ResourceReferenceCollection returned by
+ *            {@link #newResourceReferenceCollection()} and passed to all the methods that take a
+ *            ResourceReferenceCollection. You will typically just use ResourceReferenceCollection
+ *            for this param, unless you are returning a specific type of
+ *            ResourceReferenceCollection from your subclass.
+ * @param <K>
+ *            the class of the key that you will create from
+ *            {@link #newGroupingKey(ResourceReferenceAndStringData)}
+ */
+public abstract class AbstractResourceAggregatingHeaderResponse<R extends ResourceReferenceCollection, K>
+	extends DecoratingHeaderResponse
+{
+
+	private final List<ResourceReferenceAndStringData> topLevelReferences = new ArrayList<ResourceReferenceAndStringData>();
+
+	/**
+	 * Construct.
+	 * 
+	 * @param real
+	 *            the wrapped header response
+	 */
+	public AbstractResourceAggregatingHeaderResponse(IHeaderResponse real)
+	{
+		super(real);
+	}
+
+	@Override
+	public void renderJavascriptReference(ResourceReference reference)
+	{
+		topLevelReferences.add(new ResourceReferenceAndStringData(reference, null, false));
+	}
+
+	@Override
+	public void renderJavascriptReference(ResourceReference reference, String id)
+	{
+		topLevelReferences.add(new ResourceReferenceAndStringData(reference, id, false));
+	}
+
+	@Override
+	public void renderCSSReference(ResourceReference reference)
+	{
+		topLevelReferences.add(new ResourceReferenceAndStringData(reference, null, true));
+	}
+
+	@Override
+	public void renderCSSReference(ResourceReference reference, String media)
+	{
+		topLevelReferences.add(new ResourceReferenceAndStringData(reference, media, true));
+	}
+
+	@Override
+	public void close()
+	{
+		// up until now, no ResourceReference objects have been passed to the real response. we need
+		// to group them into top-level groups and then render those groups
+		SortedMap<K, R> map = new TreeMap<K, R>(getGroupingKeyComparator());
+		for (ResourceReferenceAndStringData ref : topLevelReferences)
+		{
+			K key = newGroupingKey(ref);
+			R coll = map.get(key);
+			if (coll == null)
+			{
+				map.put(key, coll = newResourceReferenceCollection());
+			}
+			coll.add(ref);
+		}
+
+		// now, render our groups to the real response
+		Set<ResourceReferenceAndStringData> alreadyRendered = new LinkedHashSet<ResourceReferenceAndStringData>();
+		for (Entry<K, R> entry : map.entrySet())
+		{
+			renderCollection(alreadyRendered, entry.getKey(), entry.getValue());
+		}
+
+		onAllCollectionsRendered(topLevelReferences);
+
+		// finally, we close the real response
+		super.close();
+	}
+
+	/* methods designed to be overridden if needed */
+	/**
+	 * creates a ResourceReferenceCollection. If you want a specific type of
+	 * ResourceReferenceCollection for your subclass of
+	 * {@link AbstractResourceAggregatingHeaderResponse}, override this method.
+	 * 
+	 * Note that because of the generics definition, you will probably have to cast to R. R is the
+	 * parameter used when creating your subclass defining the type of ResourceReferenceCollection
+	 * this returns and is passed into all methods that take a ResourceReferenceCollection
+	 * 
+	 * @return a newly created collection to contain resource references
+	 */
+	@SuppressWarnings("unchecked")
+	protected R newResourceReferenceCollection()
+	{
+		return (R)new ResourceReferenceCollection();
+	}
+
+	/**
+	 * This key is what is used to determine how to group (or aggregate) your resources. It must
+	 * implement equals and hashCode correctly so that it can be used as a key in a HashMap. These
+	 * methods must be implemented so that if two references are given over the course of the
+	 * hierarchy traversal, and those two references should be grouped (or aggregated), the keys
+	 * returned for each should equal each other and their hash codes should be equal as well.
+	 * 
+	 * Typical implementations should use whether or not the resource reference is CSS as their
+	 * first grouping parameter, since you don't want to render JS and CSS in the same tag (one
+	 * needs to be in a link tag and one in a script tag).
+	 * 
+	 * Note that if your grouping key class (K) does not implement Comparable&lt;K&gt;, you must
+	 * also override {@link #getGroupingKeyComparator()} and return a valid comparator that sorts
+	 * keys in the order you want references rendered.
+	 * 
+	 * @param ref
+	 *            the resource reference with associated data that came from the render*Reference
+	 *            methods
+	 * @return a new key used to group the references.
+	 */
+	protected abstract K newGroupingKey(ResourceReferenceAndStringData ref);
+
+	/**
+	 * This comparator is used to sort the grouping keys that you return from
+	 * {@link #newGroupingKey(ResourceReferenceAndStringData)}.
+	 * 
+	 * Note that if your grouping key class (K) implements Comparable&lt;K&gt;, you do not need to
+	 * override this method.
+	 * 
+	 * @return a Comparator for K
+	 */
+	protected Comparator<K> getGroupingKeyComparator()
+	{
+		return null;
+	}
+
+	/**
+	 * When the entire hierarchy has been traversed and {@link #close()} is called, we loop through
+	 * the grouped collections and render them in this method. This method is typically overridden
+	 * to render your collection how you want to render them.
+	 * 
+	 * For instance, if you want to aggregate your groups into a single HTTP request, you can
+	 * override this method, create the URL to your aggregation servlet (or {@link Resource}), and
+	 * then call <tt>getRealResponse().renderJavascriptReference(yourUrl)</tt>, or the appropriate
+	 * method to render the URL for a group of CSS references.
+	 * 
+	 * @param alreadyRendered
+	 *            a set of resource references that have already been rendered in other groups
+	 * @param key
+	 *            they grouping key for this group
+	 * @param coll
+	 *            the collection of resource references to render
+	 */
+	protected void renderCollection(Set<ResourceReferenceAndStringData> alreadyRendered, K key,
+		R coll)
+	{
+		for (ResourceReferenceAndStringData data : coll)
+		{
+			renderIfNotAlreadyRendered(alreadyRendered, data);
+		}
+	}
+
+	/**
+	 * Renders a single resource reference, only if it has not already been rendered. Note that you
+	 * will typically not need to override this method. You should typically override
+	 * {@link #render(ResourceReferenceAndStringData)} directly, which is called from this method if
+	 * the resource reference has not been rendered elsewhere.
+	 * 
+	 * @param alreadyRendered
+	 *            the set of references that have already been rendered in other groups
+	 * @param data
+	 *            the reference (and associated data) to conditionally render.
+	 */
+	protected void renderIfNotAlreadyRendered(Set<ResourceReferenceAndStringData> alreadyRendered,
+		ResourceReferenceAndStringData data)
+	{
+		if (!alreadyRendered.contains(data))
+		{
+			render(data);
+			alreadyRendered.add(data);
+		}
+	}
+
+	/**
+	 * Renders a single resource reference. This is called from
+	 * {@link #renderIfNotAlreadyRendered(Set, ResourceReferenceAndStringData)} for references that
+	 * had not been rendered elsewhere.
+	 * 
+	 * @param data
+	 *            the reference (and associated data) to conditionally render.
+	 */
+	protected void render(ResourceReferenceAndStringData data)
+	{
+		ResourceUtil.renderTo(getRealResponse(), data.getReference(), data.isCss(),
+			data.getString());
+	}
+
+	/**
+	 * After all the collections have been rendered, we call this callback so your subclass can add
+	 * any other logic as needed. For instance, if you are aggregating YUI resources, your
+	 * {@link #renderCollection(Set, Object, ResourceReferenceCollection)} method might have
+	 * rendered only a YUI constructor that loaded all the JS files for each group. Then, you need
+	 * to loop through the references again, and render any JS inside a sandboxed YUI.use()
+	 * statement. You would render those here by creating the YUI.use statement, and call
+	 * <tt>getHeaderResponse().renderJavascript(yourJS, null)</tt>
+	 * 
+	 * @param allTopLevelReferences
+	 *            all the references that were rendered by the developers
+	 */
+	protected void onAllCollectionsRendered(
+		List<ResourceReferenceAndStringData> allTopLevelReferences)
+	{
+
+	}
+
+	/* other interface methods: */
+	@Override
+	public void renderJavascriptReference(String url)
+	{
+		// TODO: can we aggregate this? probably shouldn't...
+		getRealResponse().renderJavascriptReference(url);
+	}
+
+	@Override
+	public void renderJavascriptReference(String url, String id)
+	{
+		// TODO: can we aggregate this? probably shouldn't...
+		getRealResponse().renderJavascriptReference(url, id);
+	}
+
+	@Override
+	public void renderCSSReference(String url)
+	{
+		// TODO: can we aggregate this? probably shouldn't...
+		getRealResponse().renderCSSReference(url);
+	}
+
+	@Override
+	public void renderCSSReference(String url, String media)
+	{
+		// TODO: can we aggregate this? probably shouldn't...
+		getRealResponse().renderCSSReference(url, media);
+	}
+
+}

Added: wicket/trunk/wicket/src/main/java/org/apache/wicket/resource/aggregation/ResourceReferenceAndStringData.java
URL: http://svn.apache.org/viewvc/wicket/trunk/wicket/src/main/java/org/apache/wicket/resource/aggregation/ResourceReferenceAndStringData.java?rev=1033801&view=auto
==============================================================================
--- wicket/trunk/wicket/src/main/java/org/apache/wicket/resource/aggregation/ResourceReferenceAndStringData.java (added)
+++ wicket/trunk/wicket/src/main/java/org/apache/wicket/resource/aggregation/ResourceReferenceAndStringData.java Thu Nov 11 02:12:01 2010
@@ -0,0 +1,124 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.wicket.resource.aggregation;
+
+import org.apache.wicket.ResourceReference;
+
+/**
+ * A data holder built for the {@link AbstractResourceAggregatingHeaderResponse} that groups the
+ * resource reference with a boolean representing whether it is css (or, if not, it is js), and the
+ * string that was passed in to the responsible render*Reference method (for JS, this is ID, for
+ * CSS, this is media).
+ * 
+ * It acts as a temporary data holder while the IHeaderContributors are being called so that at the
+ * end of their traversal, we can render these references in an aggregated way, and still have the
+ * appropriate data (i.e. was it CSS or JS) to render it properly.
+ * 
+ * @author Jeremy Thomerson
+ */
+public class ResourceReferenceAndStringData
+{
+	private final ResourceReference reference;
+	private final String string;
+	private final boolean css;
+
+	/**
+	 * Construct with fields.
+	 * 
+	 * @param reference
+	 * @param string
+	 * @param css
+	 */
+	public ResourceReferenceAndStringData(ResourceReference reference, String string, boolean css)
+	{
+		super();
+		this.reference = reference;
+		this.string = string;
+		this.css = css;
+	}
+
+	/**
+	 * @return the resource reference that the user rendered
+	 */
+	public ResourceReference getReference()
+	{
+		return reference;
+	}
+
+	/**
+	 * @return the string representing media (if this isCss()), or id (if not, meaning it's js)
+	 */
+	public String getString()
+	{
+		return string;
+	}
+
+	/**
+	 * @return true if this is css, false if it's js
+	 */
+	public boolean isCss()
+	{
+		return css;
+	}
+
+	@Override
+	public int hashCode()
+	{
+		final int prime = 31;
+		int result = 1;
+		result = prime * result + (css ? 1231 : 1237);
+		result = prime * result + ((reference == null) ? 0 : reference.hashCode());
+		result = prime * result + ((string == null) ? 0 : string.hashCode());
+		return result;
+	}
+
+	@Override
+	public boolean equals(Object obj)
+	{
+		if (this == obj)
+			return true;
+		if (obj == null)
+			return false;
+		if (getClass() != obj.getClass())
+			return false;
+		ResourceReferenceAndStringData other = (ResourceReferenceAndStringData)obj;
+		if (css != other.css)
+			return false;
+		if (reference == null)
+		{
+			if (other.reference != null)
+				return false;
+		}
+		else if (!reference.equals(other.reference))
+			return false;
+		if (string == null)
+		{
+			if (other.string != null)
+				return false;
+		}
+		else if (!string.equals(other.string))
+			return false;
+		return true;
+	}
+
+	@Override
+	public String toString()
+	{
+		return "ResourceReferenceAndStringData [reference=" + reference + ", string=" + string +
+			", css=" + css + "]";
+	}
+}
\ No newline at end of file

Added: wicket/trunk/wicket/src/main/java/org/apache/wicket/resource/aggregation/ResourceReferenceCollection.java
URL: http://svn.apache.org/viewvc/wicket/trunk/wicket/src/main/java/org/apache/wicket/resource/aggregation/ResourceReferenceCollection.java?rev=1033801&view=auto
==============================================================================
--- wicket/trunk/wicket/src/main/java/org/apache/wicket/resource/aggregation/ResourceReferenceCollection.java (added)
+++ wicket/trunk/wicket/src/main/java/org/apache/wicket/resource/aggregation/ResourceReferenceCollection.java Thu Nov 11 02:12:01 2010
@@ -0,0 +1,50 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.wicket.resource.aggregation;
+
+import java.util.Collection;
+import java.util.LinkedHashSet;
+
+/**
+ * Just a LinkedHashSet that stores a collection of resource references. You can create additional
+ * methods that your header response might need.
+ * 
+ * @author Jeremy Thomerson
+ */
+public class ResourceReferenceCollection extends LinkedHashSet<ResourceReferenceAndStringData>
+{
+	private static final long serialVersionUID = 1L;
+
+	/**
+	 * Just chains to super constructor.
+	 */
+	public ResourceReferenceCollection()
+	{
+		super();
+	}
+
+	/**
+	 * Just chains to super constructor.
+	 * 
+	 * @param c
+	 */
+	public ResourceReferenceCollection(Collection<? extends ResourceReferenceAndStringData> c)
+	{
+		super(c);
+	}
+
+}

Added: wicket/trunk/wicket/src/main/java/org/apache/wicket/resource/dependencies/AbstractResourceDependentResourceReference.java
URL: http://svn.apache.org/viewvc/wicket/trunk/wicket/src/main/java/org/apache/wicket/resource/dependencies/AbstractResourceDependentResourceReference.java?rev=1033801&view=auto
==============================================================================
--- wicket/trunk/wicket/src/main/java/org/apache/wicket/resource/dependencies/AbstractResourceDependentResourceReference.java (added)
+++ wicket/trunk/wicket/src/main/java/org/apache/wicket/resource/dependencies/AbstractResourceDependentResourceReference.java Thu Nov 11 02:12:01 2010
@@ -0,0 +1,170 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.wicket.resource.dependencies;
+
+import java.util.Locale;
+
+import org.apache.wicket.ResourceReference;
+import org.apache.wicket.markup.html.IHeaderResponse;
+import org.apache.wicket.util.string.Strings;
+
+/**
+ * A resource reference that also has resources that it is dependent on. For instance, you may have
+ * foo.js that calls functions defined in base-utils.js. By creating a ResourceReference for foo.js,
+ * your {@link IResourceReferenceDependencyConfigurationService} can create an
+ * AbstractResourceDependentResourceReference that has base-utils.js as its dependency.
+ * 
+ * @see IResourceReferenceDependencyConfigurationService
+ * @author Jeremy Thomerson
+ */
+public abstract class AbstractResourceDependentResourceReference extends ResourceReference
+{
+
+	private static final long serialVersionUID = 1L;
+
+	/**
+	 * The type of resource that an AbstractResourceDependentResourceReference represents.
+	 * 
+	 * @author Jeremy Thomerson
+	 */
+	public enum ResourceType {
+		/**
+		 * Javascript reference
+		 */
+		JS,
+
+		/**
+		 * CSS reference
+		 */
+		CSS
+	}
+
+	private String uniqueId;
+	private String media;
+
+	/**
+	 * Construct.
+	 * 
+	 * @param scope
+	 * @param name
+	 * @param locale
+	 * @param style
+	 */
+	public AbstractResourceDependentResourceReference(Class<?> scope, String name, Locale locale,
+		String style)
+	{
+		super(scope, name, locale, style);
+	}
+
+	/**
+	 * Construct.
+	 * 
+	 * @param scope
+	 * @param name
+	 */
+	public AbstractResourceDependentResourceReference(Class<?> scope, String name)
+	{
+		super(scope, name);
+	}
+
+	/**
+	 * Construct.
+	 * 
+	 * @param name
+	 */
+	public AbstractResourceDependentResourceReference(String name)
+	{
+		super(name);
+	}
+
+	/**
+	 * A globally-unique (to your application(s)) ID for this resource reference. This is optional,
+	 * and is set for you if you call IHeaderResponse.renderJavascriptReference(yourReference,
+	 * "some-id").
+	 * 
+	 * @param uniqueId
+	 */
+	public void setUniqueId(String uniqueId)
+	{
+		this.uniqueId = uniqueId;
+	}
+
+	/**
+	 * A globally-unique (to your application(s)) ID for this resource reference. This is optional,
+	 * and is set for you if you call IHeaderResponse.renderJavascriptReference(yourReference,
+	 * "some-id").
+	 * 
+	 * @return globally-unique (to your application(s)) ID for this resource reference
+	 */
+	public String getUniqueId()
+	{
+		return uniqueId;
+	}
+
+	/**
+	 * If you call
+	 * ResourceReferenceDependencyInjectingHeaderResponse.renderCSSReference(yourReference,
+	 * "some-media"), the media is set in this field so that it can later render itself properly to
+	 * the wrapped IHeaderResponse
+	 * 
+	 * @param media
+	 */
+	public void setMedia(String media)
+	{
+		this.media = media;
+	}
+
+	/**
+	 * If you call
+	 * ResourceReferenceDependencyInjectingHeaderResponse.renderCSSReference(yourReference,
+	 * "some-media"), the media is set in this field so that it can later render itself properly to
+	 * the wrapped IHeaderResponse
+	 * 
+	 * @return the media set on calling
+	 *         ResourceReferenceDependencyInjectingHeaderResponse.renderCSSReference(yourReference,
+	 *         "some-media")
+	 */
+	public String getMedia()
+	{
+		return media;
+	}
+
+	/**
+	 * Defaults to returning JS, but returns CSS if the name property ends with ".css".
+	 * 
+	 * You can override this method if you need more sophisticated behavior.
+	 * 
+	 * @return the ResourceType this reference represents, so that it can be properly added to the
+	 *         {@link IHeaderResponse}
+	 */
+	public ResourceType getResourceType()
+	{
+		if (!Strings.isEmpty(getName()) && getName().endsWith(".css"))
+		{
+			return ResourceType.CSS;
+		}
+		return ResourceType.JS;
+	}
+
+	/**
+	 * Returns all ResourceReferences that this ResourceReference is depending on.
+	 * 
+	 * @return all ResourceReferences that this ResourceReference is depending on.
+	 */
+	public abstract AbstractResourceDependentResourceReference[] getDependentResourceReferences();
+
+}

Added: wicket/trunk/wicket/src/main/java/org/apache/wicket/resource/dependencies/IResourceReferenceDependencyConfigurationService.java
URL: http://svn.apache.org/viewvc/wicket/trunk/wicket/src/main/java/org/apache/wicket/resource/dependencies/IResourceReferenceDependencyConfigurationService.java?rev=1033801&view=auto
==============================================================================
--- wicket/trunk/wicket/src/main/java/org/apache/wicket/resource/dependencies/IResourceReferenceDependencyConfigurationService.java (added)
+++ wicket/trunk/wicket/src/main/java/org/apache/wicket/resource/dependencies/IResourceReferenceDependencyConfigurationService.java Thu Nov 11 02:12:01 2010
@@ -0,0 +1,48 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.wicket.resource.dependencies;
+
+import org.apache.wicket.ResourceReference;
+
+/**
+ * You must implement this in order to use ResourceReferenceDependencyInjectingHeaderResponse. It is
+ * passed into the ResourceReferenceDependencyInjectingHeaderResponse constructor, and that header
+ * response uses it to determine dependencies for all resources.
+ * 
+ * @see ResourceReferenceDependencyInjectingHeaderResponse
+ * @author Jeremy Thomerson
+ */
+public interface IResourceReferenceDependencyConfigurationService
+{
+
+	/**
+	 * Takes a resource reference and returns a reference that is configured with the entire
+	 * dependency tree for this reference populated.
+	 * 
+	 * Note: this method can not return null for any reference, even those that are not configured
+	 * within it. That means that it may have the resource reference for wicket-ajax.js and other
+	 * wicket-related (or other library's) references passed in, and it must turn those into an
+	 * {@link AbstractResourceDependentResourceReference}, even if the dependencies of that
+	 * reference are empty. This ensures that later IHeaderResponse's in your decoration chain can
+	 * always rely on receiving the proper type of resource reference.
+	 * 
+	 * @param reference
+	 *            the reference that you need to look up dependencies for
+	 * @return the reference that has the entire dependency tree (all depths) populated
+	 */
+	AbstractResourceDependentResourceReference configure(ResourceReference reference);
+}

Added: wicket/trunk/wicket/src/main/java/org/apache/wicket/resource/dependencies/ResourceDependentResourceReference.java
URL: http://svn.apache.org/viewvc/wicket/trunk/wicket/src/main/java/org/apache/wicket/resource/dependencies/ResourceDependentResourceReference.java?rev=1033801&view=auto
==============================================================================
--- wicket/trunk/wicket/src/main/java/org/apache/wicket/resource/dependencies/ResourceDependentResourceReference.java (added)
+++ wicket/trunk/wicket/src/main/java/org/apache/wicket/resource/dependencies/ResourceDependentResourceReference.java Thu Nov 11 02:12:01 2010
@@ -0,0 +1,84 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.wicket.resource.dependencies;
+
+import java.util.Locale;
+
+/**
+ * A basic implementation of {@link AbstractResourceDependentResourceReference} that contains an
+ * array of {@link AbstractResourceDependentResourceReference} dependencies that must be passed in
+ * at construction time.
+ * 
+ * @author Jeremy Thomerson
+ */
+public class ResourceDependentResourceReference extends AbstractResourceDependentResourceReference
+{
+
+	private static final long serialVersionUID = 1L;
+
+	private final AbstractResourceDependentResourceReference[] dependencies;
+
+	/**
+	 * Construct.
+	 * 
+	 * @param scope
+	 * @param name
+	 * @param locale
+	 * @param style
+	 * @param dependencies
+	 */
+	public ResourceDependentResourceReference(Class<?> scope, String name, Locale locale,
+		String style, AbstractResourceDependentResourceReference[] dependencies)
+	{
+		super(scope, name, locale, style);
+		this.dependencies = dependencies;
+	}
+
+	/**
+	 * Construct.
+	 * 
+	 * @param scope
+	 * @param name
+	 * @param dependencies
+	 */
+	public ResourceDependentResourceReference(Class<?> scope, String name,
+		AbstractResourceDependentResourceReference[] dependencies)
+	{
+		super(scope, name);
+		this.dependencies = dependencies;
+	}
+
+	/**
+	 * Construct.
+	 * 
+	 * @param name
+	 * @param dependencies
+	 */
+	public ResourceDependentResourceReference(String name,
+		AbstractResourceDependentResourceReference[] dependencies)
+	{
+		super(name);
+		this.dependencies = dependencies;
+	}
+
+	@Override
+	public final AbstractResourceDependentResourceReference[] getDependentResourceReferences()
+	{
+		return dependencies;
+	}
+
+}

Added: wicket/trunk/wicket/src/main/java/org/apache/wicket/resource/dependencies/ResourceReferenceDependencyInjectingHeaderResponse.java
URL: http://svn.apache.org/viewvc/wicket/trunk/wicket/src/main/java/org/apache/wicket/resource/dependencies/ResourceReferenceDependencyInjectingHeaderResponse.java?rev=1033801&view=auto
==============================================================================
--- wicket/trunk/wicket/src/main/java/org/apache/wicket/resource/dependencies/ResourceReferenceDependencyInjectingHeaderResponse.java (added)
+++ wicket/trunk/wicket/src/main/java/org/apache/wicket/resource/dependencies/ResourceReferenceDependencyInjectingHeaderResponse.java Thu Nov 11 02:12:01 2010
@@ -0,0 +1,150 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.wicket.resource.dependencies;
+
+import org.apache.wicket.ResourceReference;
+import org.apache.wicket.markup.html.DecoratingHeaderResponse;
+import org.apache.wicket.markup.html.IHeaderResponse;
+import org.apache.wicket.markup.html.IHeaderResponseDecorator;
+import org.apache.wicket.resource.ResourceUtil;
+import org.apache.wicket.resource.dependencies.AbstractResourceDependentResourceReference.ResourceType;
+
+/**
+ * A header response that can be used by {@link IHeaderResponseDecorator} to wrap another
+ * IHeaderResponse. This response will take all references (js and css) and pass them to the
+ * {@link IResourceReferenceDependencyConfigurationService} to get the dependency tree populated.
+ * After this, it will call through to the wrapped header response and render the tree in the
+ * child-first dependency order so that all dependencies are guaranteed to be satisfied before this
+ * reference is rendered.
+ * 
+ * @author Jeremy Thomerson
+ */
+public class ResourceReferenceDependencyInjectingHeaderResponse extends DecoratingHeaderResponse
+{
+
+	private final IResourceReferenceDependencyConfigurationService configurationService;
+
+	/**
+	 * If you call this constructor, you MUST override getConfigurationService().
+	 * 
+	 * @param decorated
+	 *            the response you are decorating
+	 */
+	public ResourceReferenceDependencyInjectingHeaderResponse(IHeaderResponse decorated)
+	{
+		this(decorated, null);
+	}
+
+	/**
+	 * Construct this header response with a configuration service that will be used to find
+	 * dependencies.
+	 * 
+	 * @param decorated
+	 *            the response you are decorating
+	 * @param configurator
+	 *            the configuration service
+	 */
+	public ResourceReferenceDependencyInjectingHeaderResponse(IHeaderResponse decorated,
+		IResourceReferenceDependencyConfigurationService configurator)
+	{
+		super(decorated);
+		configurationService = configurator;
+	}
+
+	/**
+	 * If you did not supply a non-null configuration service in the constructor, you must override
+	 * this to return a configuration service to be used by this response.
+	 * 
+	 * @return the configuration service used by this response
+	 */
+	public IResourceReferenceDependencyConfigurationService getConfigurationService()
+	{
+		if (configurationService == null)
+		{
+			throw new IllegalStateException(
+				"you must either provide an IResourceReferenceDependencyConfigurationService at construction time or override getConfigurationService()");
+		}
+		return configurationService;
+	}
+
+	/* overridden IHeaderResponse methods: */
+	@Override
+	public void renderCSSReference(ResourceReference reference)
+	{
+		render(get(reference));
+	}
+
+	@Override
+	public void renderCSSReference(ResourceReference reference, String media)
+	{
+		AbstractResourceDependentResourceReference parent = get(reference);
+		parent.setMedia(media);
+		render(parent);
+	}
+
+	@Override
+	public void renderJavascriptReference(ResourceReference reference)
+	{
+		render(get(reference));
+	}
+
+	@Override
+	public void renderJavascriptReference(ResourceReference reference, String id)
+	{
+		AbstractResourceDependentResourceReference parent = get(reference);
+		parent.setUniqueId(id);
+		render(parent);
+	}
+
+	/**
+	 * The method responsible for rendering the resource references. This should happen child-first
+	 * so that the dependencies (children) of the given parent are loaded first, thereby satisfying
+	 * the dependencies of the supplied parent.
+	 * 
+	 * Typically the actual rendering will happen on the response that this response is wrapping.
+	 * The default implementation does all rendering to the wrapped response.
+	 * 
+	 * The default implementation delegates the actual rendering to the
+	 * AbstractResourceDependentResourceReference itself.
+	 * 
+	 * @param parent
+	 *            the reference that needs itself and all dependencies to be rendered
+	 */
+	protected void render(AbstractResourceDependentResourceReference parent)
+	{
+		for (AbstractResourceDependentResourceReference child : parent.getDependentResourceReferences())
+		{
+			render(child);
+		}
+		boolean css = ResourceType.CSS.equals(parent.getResourceType());
+		String string = css ? parent.getMedia() : parent.getUniqueId();
+		ResourceUtil.renderTo(getRealResponse(), parent, css, string);
+	}
+
+	private AbstractResourceDependentResourceReference get(ResourceReference reference)
+	{
+		AbstractResourceDependentResourceReference ref = getConfigurationService().configure(
+			reference);
+		if (ref == null)
+		{
+			throw new IllegalStateException(
+				"your IResourceReferenceDependencyConfigurationService can not return null from configure");
+		}
+		return ref;
+	}
+
+}

Added: wicket/trunk/wicket/src/main/java/org/apache/wicket/resource/filtering/AbstractHeaderResponseFilter.java
URL: http://svn.apache.org/viewvc/wicket/trunk/wicket/src/main/java/org/apache/wicket/resource/filtering/AbstractHeaderResponseFilter.java?rev=1033801&view=auto
==============================================================================
--- wicket/trunk/wicket/src/main/java/org/apache/wicket/resource/filtering/AbstractHeaderResponseFilter.java (added)
+++ wicket/trunk/wicket/src/main/java/org/apache/wicket/resource/filtering/AbstractHeaderResponseFilter.java Thu Nov 11 02:12:01 2010
@@ -0,0 +1,64 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.wicket.resource.filtering;
+
+import org.apache.wicket.ResourceReference;
+import org.apache.wicket.resource.filtering.HeaderResponseContainerFilteringHeaderResponse.IHeaderResponseFilter;
+
+/**
+ * A default implementation of IHeaderResponseFilter that returns true for everything. It is defined
+ * as abstract because you are not supposed to use it directly, but use it as a base and override
+ * any methods that you need to return something other than true from (whether that's always false
+ * or conditional logic).
+ * 
+ * @author Jeremy Thomerson
+ */
+public abstract class AbstractHeaderResponseFilter implements IHeaderResponseFilter
+{
+
+	private final String name;
+
+	/**
+	 * Create a response filter.
+	 * 
+	 * @param name
+	 */
+	public AbstractHeaderResponseFilter(String name)
+	{
+		this.name = name;
+	}
+
+	public String getName()
+	{
+		return name;
+	}
+
+	public boolean acceptReference(ResourceReference object)
+	{
+		return true;
+	}
+
+	public boolean acceptOtherJavascript()
+	{
+		return true;
+	}
+
+	public boolean acceptOtherCss()
+	{
+		return true;
+	}
+}

Added: wicket/trunk/wicket/src/main/java/org/apache/wicket/resource/filtering/CssAcceptingHeaderResponseFilter.java
URL: http://svn.apache.org/viewvc/wicket/trunk/wicket/src/main/java/org/apache/wicket/resource/filtering/CssAcceptingHeaderResponseFilter.java?rev=1033801&view=auto
==============================================================================
--- wicket/trunk/wicket/src/main/java/org/apache/wicket/resource/filtering/CssAcceptingHeaderResponseFilter.java (added)
+++ wicket/trunk/wicket/src/main/java/org/apache/wicket/resource/filtering/CssAcceptingHeaderResponseFilter.java Thu Nov 11 02:12:01 2010
@@ -0,0 +1,70 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.wicket.resource.filtering;
+
+import org.apache.wicket.ResourceReference;
+import org.apache.wicket.resource.dependencies.AbstractResourceDependentResourceReference;
+import org.apache.wicket.resource.dependencies.AbstractResourceDependentResourceReference.ResourceType;
+import org.apache.wicket.util.string.Strings;
+
+/**
+ * This filter accepts anything that appears to be CSS. All CSS that is not a resource reference (
+ * {@link #acceptOtherCss()}) is accepted. All JS that is not a resource reference (
+ * {@link #acceptOtherJavascript()}) is not accepted.
+ * 
+ * The references are accepted if they appear to be CSS. If the reference passed in is an instance
+ * of {@link AbstractResourceDependentResourceReference}, we use the {@link ResourceType} from it to
+ * determine if it is CSS. Otherwise, we see if the ResourceReference.name property ends with
+ * ".css".
+ * 
+ * @author Jeremy Thomerson
+ */
+public class CssAcceptingHeaderResponseFilter extends AbstractHeaderResponseFilter
+{
+
+	/**
+	 * Construct.
+	 * 
+	 * @param name
+	 *            name of the filter (used by the container that renders these resources)
+	 */
+	public CssAcceptingHeaderResponseFilter(String name)
+	{
+		super(name);
+	}
+
+	@Override
+	public boolean acceptReference(ResourceReference ref)
+	{
+		if (ref instanceof AbstractResourceDependentResourceReference)
+		{
+			return ResourceType.CSS.equals(((AbstractResourceDependentResourceReference)ref).getResourceType());
+		}
+		if (!Strings.isEmpty(ref.getName()) && ref.getName().endsWith(".css"))
+		{
+			return true;
+		}
+		return false;
+	}
+
+	@Override
+	public boolean acceptOtherJavascript()
+	{
+		return false;
+	}
+
+}

Added: wicket/trunk/wicket/src/main/java/org/apache/wicket/resource/filtering/HeaderResponseContainerFilteringHeaderResponse.java
URL: http://svn.apache.org/viewvc/wicket/trunk/wicket/src/main/java/org/apache/wicket/resource/filtering/HeaderResponseContainerFilteringHeaderResponse.java?rev=1033801&view=auto
==============================================================================
--- wicket/trunk/wicket/src/main/java/org/apache/wicket/resource/filtering/HeaderResponseContainerFilteringHeaderResponse.java (added)
+++ wicket/trunk/wicket/src/main/java/org/apache/wicket/resource/filtering/HeaderResponseContainerFilteringHeaderResponse.java Thu Nov 11 02:12:01 2010
@@ -0,0 +1,404 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.wicket.resource.filtering;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import org.apache.wicket.Component;
+import org.apache.wicket.MetaDataKey;
+import org.apache.wicket.RequestCycle;
+import org.apache.wicket.ResourceReference;
+import org.apache.wicket.Response;
+import org.apache.wicket.ajax.AjaxRequestTarget;
+import org.apache.wicket.markup.html.DecoratingHeaderResponse;
+import org.apache.wicket.markup.html.IHeaderResponse;
+import org.apache.wicket.response.StringResponse;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * This header response allows you to separate things that are added to the IHeaderResponse into
+ * different buckets. Then, you can render those different buckets in separate areas of the page
+ * based on your filter logic. A typical use case for this header response is to move the loading of
+ * Javascript files (and inline script tags) to the footer of the page.
+ * 
+ * @see HeaderResponseFilteredResponseContainer
+ * @see CssAcceptingHeaderResponseFilter
+ * @see JavascriptAcceptingHeaderResponseFilter
+ * @author Jeremy Thomerson
+ */
+public class HeaderResponseContainerFilteringHeaderResponse extends DecoratingHeaderResponse
+{
+
+	private static final Logger log = LoggerFactory.getLogger(Component.class);
+
+	/**
+	 * A filter used to bucket your resources, inline scripts, etc, into different responses. The
+	 * bucketed resources are then rendered by a {@link HeaderResponseFilteredResponseContainer},
+	 * using the name of the filter to get the correct bucket.
+	 * 
+	 * @author Jeremy Thomerson
+	 */
+	public static interface IHeaderResponseFilter
+	{
+		/**
+		 * @return name of the filter (used by the container that renders these resources)
+		 */
+		String getName();
+
+		/**
+		 * Determines whether a given ResourceReference should be rendered in the bucket represented
+		 * by this filter.
+		 * 
+		 * @param ref
+		 *            the reference to be rendered
+		 * @return true if it should be bucketed with other things in this filter
+		 */
+		boolean acceptReference(ResourceReference ref);
+
+		/**
+		 * Whenever a render*Javascript method on IHeaderResponse is called that is not a
+		 * ResourceReference (i.e. {@link IHeaderResponse#renderOnDomReadyJavascript(String)}), this
+		 * method determines if the script should be bucketed with other things in this filter.
+		 * 
+		 * Note that calls to IHeaderResponse.renderJavascriptReference(String url) are also
+		 * filtered with this method since there is no actual ResourceReference to pass
+		 * 
+		 * @return true if javascript should be bucketed with other things in this filter
+		 */
+		boolean acceptOtherJavascript();
+
+		/**
+		 * Whenever a renderCSS* method on IHeaderResponse is called that is not a ResourceReference
+		 * (i.e. {@link IHeaderResponse#renderCSSReference(String)}, or
+		 * {@link IHeaderResponse#renderCSSReference(String, String)}), this method determines if
+		 * the CSS reference should be bucketed with other things in this filter.
+		 * 
+		 * @return true if css should be bucketed with other things in this filter
+		 */
+		boolean acceptOtherCss();
+	}
+
+	/**
+	 * we store this HeaderResponseContainerFilteringHeaderResponse in the RequestCycle so that the
+	 * containers can access it to render their bucket of stuff
+	 */
+	private static final MetaDataKey<HeaderResponseContainerFilteringHeaderResponse> RESPONSE_KEY = new MetaDataKey<HeaderResponseContainerFilteringHeaderResponse>()
+	{
+		private static final long serialVersionUID = 1L;
+	};
+
+	private final Map<String, StringResponse> responseFilterMap = new HashMap<String, StringResponse>();
+	private IHeaderResponseFilter[] filters;
+	private final String headerFilterName;
+
+	/**
+	 * Construct.
+	 * 
+	 * @param response
+	 *            the wrapped IHeaderResponse
+	 * @param headerFilterName
+	 *            the name that the filter for things that should appear in the head (default Wicket
+	 *            location) uses
+	 * @param filters
+	 *            the filters to use to bucket things. There will be a bucket created for each
+	 *            filter, by name. There should typically be at least one filter with the same name
+	 *            as your headerFilterName
+	 */
+	public HeaderResponseContainerFilteringHeaderResponse(IHeaderResponse response,
+		String headerFilterName, IHeaderResponseFilter[] filters)
+	{
+		super(response);
+		this.headerFilterName = headerFilterName;
+
+		setFilters(filters);
+
+		RequestCycle.get().setMetaData(RESPONSE_KEY, this);
+	}
+
+	protected void setFilters(IHeaderResponseFilter[] filters)
+	{
+		this.filters = filters;
+		if (filters == null)
+		{
+			return;
+		}
+		for (IHeaderResponseFilter filter : filters)
+		{
+			responseFilterMap.put(filter.getName(), new StringResponse());
+		}
+	}
+
+	/**
+	 * @return the HeaderResponseContainerFilteringHeaderResponse being used in this RequestCycle
+	 */
+	public static HeaderResponseContainerFilteringHeaderResponse get()
+	{
+		RequestCycle requestCycle = RequestCycle.get();
+		if (requestCycle == null)
+		{
+			throw new IllegalStateException(
+				"you can only get the HeaderResponseContainerFilteringHeaderResponse when there is a RequestCycle present");
+		}
+		HeaderResponseContainerFilteringHeaderResponse response = requestCycle.getMetaData(RESPONSE_KEY);
+		if (response == null)
+		{
+			throw new IllegalStateException(
+				"no HeaderResponseContainerFilteringHeaderResponse is present in the request cycle.  This may mean that you have not decorated the header response with a HeaderResponseContainerFilteringHeaderResponse.  Simply calling the HeaderResponseContainerFilteringHeaderResponse constructor sets itself on the request cycle");
+		}
+		return response;
+	}
+
+	@Override
+	public void renderJavascriptReference(final ResourceReference reference)
+	{
+		forReference(reference, new Runnable()
+		{
+			public void run()
+			{
+				getRealResponse().renderJavascriptReference(reference);
+			}
+		});
+	}
+
+	@Override
+	public void renderJavascriptReference(final ResourceReference reference, final String id)
+	{
+		forReference(reference, new Runnable()
+		{
+			public void run()
+			{
+				getRealResponse().renderJavascriptReference(reference, id);
+			}
+		});
+	}
+
+	@Override
+	public void renderJavascriptReference(final String url)
+	{
+		forJavascript(new Runnable()
+		{
+			public void run()
+			{
+				getRealResponse().renderJavascriptReference(url);
+			}
+		});
+	}
+
+	@Override
+	public void renderJavascriptReference(final String url, final String id)
+	{
+		forJavascript(new Runnable()
+		{
+			public void run()
+			{
+				getRealResponse().renderJavascriptReference(url, id);
+			}
+		});
+	}
+
+	@Override
+	public void renderJavascript(final CharSequence javascript, final String id)
+	{
+		forJavascript(new Runnable()
+		{
+			public void run()
+			{
+				getRealResponse().renderJavascript(javascript, id);
+			}
+		});
+	}
+
+	@Override
+	public void renderCSSReference(final ResourceReference reference)
+	{
+		forReference(reference, new Runnable()
+		{
+			public void run()
+			{
+				getRealResponse().renderCSSReference(reference);
+			}
+		});
+	}
+
+	@Override
+	public void renderCSSReference(final String url)
+	{
+		forCss(new Runnable()
+		{
+			public void run()
+			{
+				getRealResponse().renderCSSReference(url);
+			}
+		});
+	}
+
+	@Override
+	public void renderCSSReference(final ResourceReference reference, final String media)
+	{
+		forReference(reference, new Runnable()
+		{
+			public void run()
+			{
+				getRealResponse().renderCSSReference(reference, media);
+			}
+		});
+	}
+
+	@Override
+	public void renderCSSReference(final String url, final String media)
+	{
+		forCss(new Runnable()
+		{
+			public void run()
+			{
+				getRealResponse().renderCSSReference(url, media);
+			}
+		});
+	}
+
+	@Override
+	public void renderOnDomReadyJavascript(final String javascript)
+	{
+		forJavascript(new Runnable()
+		{
+			public void run()
+			{
+				getRealResponse().renderOnDomReadyJavascript(javascript);
+			}
+		});
+	}
+
+	@Override
+	public void renderOnLoadJavascript(final String javascript)
+	{
+		forJavascript(new Runnable()
+		{
+			public void run()
+			{
+				getRealResponse().renderOnLoadJavascript(javascript);
+			}
+		});
+	}
+
+	@Override
+	public void renderOnEventJavascript(final String target, final String event,
+		final String javascript)
+	{
+		forJavascript(new Runnable()
+		{
+			public void run()
+			{
+				getRealResponse().renderOnEventJavascript(target, event, javascript);
+			}
+		});
+	}
+
+	@Override
+	public void close()
+	{
+		// write the stuff that was actually supposed to be in the header to the
+		// response, which is used by the built-in HtmlHeaderContainer to get
+		// its contents
+		CharSequence headerContent = getContent(headerFilterName);
+		RequestCycle.get().getResponse().write(headerContent);
+		// must make sure our super (and with it, the wrapped response) get closed:
+		super.close();
+	}
+
+	/**
+	 * Gets the content that was rendered to this header response and matched the filter with the
+	 * given name.
+	 * 
+	 * @param filterName
+	 *            the name of the filter to get the bucket for
+	 * @return the content that was accepted by the filter with this name
+	 */
+	public final CharSequence getContent(String filterName)
+	{
+		if (filterName == null)
+		{
+			return "";
+		}
+		StringResponse resp = responseFilterMap.get(filterName);
+		return resp == null ? "" : resp.getBuffer();
+	}
+
+	private void forReference(ResourceReference reference, Runnable runnable)
+	{
+		for (IHeaderResponseFilter filter : filters)
+		{
+			if (filter.acceptReference(reference))
+			{
+				run(runnable, filter);
+				return;
+			}
+		}
+		log.warn("a ResourceReference was rendered to the filtering header response, but did not match any filters, so it was effectively lost.  Make sure that you have filters that accept every possible case or else configure a default filter that returns true to all acceptance tests");
+	}
+
+	private void forJavascript(Runnable runnable)
+	{
+		for (IHeaderResponseFilter filter : filters)
+		{
+			if (filter.acceptOtherJavascript())
+			{
+				run(runnable, filter);
+				return;
+			}
+		}
+		log.warn("javascript was rendered to the filtering header response, but did not match any filters, so it was effectively lost.  Make sure that you have filters that accept every possible case or else configure a default filter that returns true to all acceptance tests");
+	}
+
+	private void forCss(Runnable runnable)
+	{
+		for (IHeaderResponseFilter filter : filters)
+		{
+			if (filter.acceptOtherCss())
+			{
+				run(runnable, filter);
+				return;
+			}
+		}
+		log.warn("css was rendered to the filtering header response, but did not match any filters, so it was effectively lost.  Make sure that you have filters that accept every possible case or else configure a default filter that returns true to all acceptance tests");
+	}
+
+	private void run(Runnable runnable, IHeaderResponseFilter filter)
+	{
+		if (AjaxRequestTarget.get() != null)
+		{
+			// we're in an ajax request, so we don't filter and separate stuff....
+			runnable.run();
+			return;
+		}
+		Response original = RequestCycle.get().setResponse(responseFilterMap.get(filter.getName()));
+		try
+		{
+			runnable.run();
+		}
+		catch (RuntimeException ex)
+		{
+			throw ex;
+		}
+		finally
+		{
+			RequestCycle.get().setResponse(original);
+		}
+	}
+
+}

Added: wicket/trunk/wicket/src/main/java/org/apache/wicket/resource/filtering/HeaderResponseFilteredResponseContainer.java
URL: http://svn.apache.org/viewvc/wicket/trunk/wicket/src/main/java/org/apache/wicket/resource/filtering/HeaderResponseFilteredResponseContainer.java?rev=1033801&view=auto
==============================================================================
--- wicket/trunk/wicket/src/main/java/org/apache/wicket/resource/filtering/HeaderResponseFilteredResponseContainer.java (added)
+++ wicket/trunk/wicket/src/main/java/org/apache/wicket/resource/filtering/HeaderResponseFilteredResponseContainer.java Thu Nov 11 02:12:01 2010
@@ -0,0 +1,73 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.wicket.resource.filtering;
+
+import org.apache.wicket.markup.ComponentTag;
+import org.apache.wicket.markup.MarkupStream;
+import org.apache.wicket.markup.html.WebMarkupContainer;
+import org.apache.wicket.markup.parser.XmlTag;
+
+/**
+ * A container that renders the content that was bucketed into a certain bucket by
+ * {@link HeaderResponseContainerFilteringHeaderResponse}.
+ * 
+ * Note that this container renders only its body by default.
+ * 
+ * @author Jeremy Thomerson
+ */
+public class HeaderResponseFilteredResponseContainer extends WebMarkupContainer
+{
+	private static final long serialVersionUID = 1L;
+
+	private final String filterName;
+
+	/**
+	 * Construct.
+	 * 
+	 * @param id
+	 *            the wicket id for this container
+	 * @param filterName
+	 *            the name of the filter that is bucketing stuff to be rendered in this container
+	 */
+	public HeaderResponseFilteredResponseContainer(String id, String filterName)
+	{
+		super(id);
+		this.filterName = filterName;
+		setRenderBodyOnly(true);
+	}
+
+	@Override
+	protected void onComponentTag(ComponentTag tag)
+	{
+		super.onComponentTag(tag);
+		// force this into an open-close tag rather than a self-closing tag
+		tag.setType(XmlTag.OPEN);
+	}
+
+	@Override
+	protected void onComponentTagBody(MarkupStream markupStream, ComponentTag openTag)
+	{
+		HeaderResponseContainerFilteringHeaderResponse response = HeaderResponseContainerFilteringHeaderResponse.get();
+		if (!response.isClosed())
+		{
+			throw new RuntimeException(
+				"there was an error processing the header response - you tried to render a bucket of response from HeaderResponseContainerFilteringHeaderResponse, but it had not yet run and been closed.  this should occur when the header container that is standard in wicket renders, so perhaps you have done something to keep that from rendering?");
+		}
+		CharSequence foot = response.getContent(filterName);
+		replaceComponentTagBody(markupStream, openTag, foot);
+	}
+}

Added: wicket/trunk/wicket/src/main/java/org/apache/wicket/resource/filtering/JavascriptAcceptingHeaderResponseFilter.java
URL: http://svn.apache.org/viewvc/wicket/trunk/wicket/src/main/java/org/apache/wicket/resource/filtering/JavascriptAcceptingHeaderResponseFilter.java?rev=1033801&view=auto
==============================================================================
--- wicket/trunk/wicket/src/main/java/org/apache/wicket/resource/filtering/JavascriptAcceptingHeaderResponseFilter.java (added)
+++ wicket/trunk/wicket/src/main/java/org/apache/wicket/resource/filtering/JavascriptAcceptingHeaderResponseFilter.java Thu Nov 11 02:12:01 2010
@@ -0,0 +1,39 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.wicket.resource.filtering;
+
+/**
+ * This filter returns the opposite of what {@link CssAcceptingHeaderResponseFilter} returns.
+ * 
+ * @see CssAcceptingHeaderResponseFilter
+ * @author Jeremy Thomerson
+ */
+public class JavascriptAcceptingHeaderResponseFilter extends OppositeHeaderResponseFilter
+{
+
+	/**
+	 * Construct.
+	 * 
+	 * @param name
+	 *            name of the filter (used by the container that renders these resources)
+	 */
+	public JavascriptAcceptingHeaderResponseFilter(String name)
+	{
+		super(name, new CssAcceptingHeaderResponseFilter("NOT_USED"));
+	}
+
+}

Added: wicket/trunk/wicket/src/main/java/org/apache/wicket/resource/filtering/JavascriptFilteredIntoFooterHeaderResponse.java
URL: http://svn.apache.org/viewvc/wicket/trunk/wicket/src/main/java/org/apache/wicket/resource/filtering/JavascriptFilteredIntoFooterHeaderResponse.java?rev=1033801&view=auto
==============================================================================
--- wicket/trunk/wicket/src/main/java/org/apache/wicket/resource/filtering/JavascriptFilteredIntoFooterHeaderResponse.java (added)
+++ wicket/trunk/wicket/src/main/java/org/apache/wicket/resource/filtering/JavascriptFilteredIntoFooterHeaderResponse.java Thu Nov 11 02:12:01 2010
@@ -0,0 +1,68 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.wicket.resource.filtering;
+
+import org.apache.wicket.markup.html.IHeaderResponse;
+
+/**
+ * A header response that creates two buckets. The header bucket will contain all references to CSS.
+ * The other bucket will contain all Javascript, and you will need to add a
+ * HeaderResponseFilteredResponseContainer to the footer of your page (typically just before the end
+ * body tag) to render the Javascript.
+ * 
+ * @author Jeremy Thomerson
+ */
+public final class JavascriptFilteredIntoFooterHeaderResponse extends
+	HeaderResponseContainerFilteringHeaderResponse
+{
+
+	private static final String HEADER_FILTER_NAME = "headerBucket";
+
+	/**
+	 * Construct.
+	 * 
+	 * @param response
+	 *            the response you are wrapping
+	 * @param footerBucketName
+	 *            the name of the bucket that you will use for your footer container (see the class
+	 *            javadocs for a reminder about putting this container in your footer)
+	 */
+	public JavascriptFilteredIntoFooterHeaderResponse(IHeaderResponse response,
+		String footerBucketName)
+	{
+		super(response, HEADER_FILTER_NAME, null);
+		setFilters(createFilters(footerBucketName));
+	}
+
+	protected IHeaderResponseFilter[] createFilters(String footerBucketName)
+	{
+		IHeaderResponseFilter header = createHeaderFilter(HEADER_FILTER_NAME);
+		IHeaderResponseFilter footer = createFooterFilter(footerBucketName);
+		return new IHeaderResponseFilter[] { header, footer };
+	}
+
+	protected JavascriptAcceptingHeaderResponseFilter createFooterFilter(String footerBucketName)
+	{
+		return new JavascriptAcceptingHeaderResponseFilter(footerBucketName);
+	}
+
+	protected CssAcceptingHeaderResponseFilter createHeaderFilter(String headerFilterName)
+	{
+		return new CssAcceptingHeaderResponseFilter(HEADER_FILTER_NAME);
+	}
+
+}

Added: wicket/trunk/wicket/src/main/java/org/apache/wicket/resource/filtering/OppositeHeaderResponseFilter.java
URL: http://svn.apache.org/viewvc/wicket/trunk/wicket/src/main/java/org/apache/wicket/resource/filtering/OppositeHeaderResponseFilter.java?rev=1033801&view=auto
==============================================================================
--- wicket/trunk/wicket/src/main/java/org/apache/wicket/resource/filtering/OppositeHeaderResponseFilter.java (added)
+++ wicket/trunk/wicket/src/main/java/org/apache/wicket/resource/filtering/OppositeHeaderResponseFilter.java Thu Nov 11 02:12:01 2010
@@ -0,0 +1,69 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.wicket.resource.filtering;
+
+import org.apache.wicket.ResourceReference;
+import org.apache.wicket.resource.filtering.HeaderResponseContainerFilteringHeaderResponse.IHeaderResponseFilter;
+
+/**
+ * A filter that takes another filter and always returns the opposite of another filter. This is
+ * useful where you have two filters (i.e. one for header and one for footer) and want to ensure
+ * that nothing ever has false returned for both cases.
+ * 
+ * @author Jeremy Thomerson
+ */
+public class OppositeHeaderResponseFilter implements IHeaderResponseFilter
+{
+
+	private final String name;
+	private final IHeaderResponseFilter other;
+
+	/**
+	 * Construct.
+	 * 
+	 * @param name
+	 *            the name used by this filter for its bucket o' stuff
+	 * @param other
+	 *            the other filter to return the opposite of
+	 */
+	public OppositeHeaderResponseFilter(String name, IHeaderResponseFilter other)
+	{
+		this.name = name;
+		this.other = other;
+	}
+
+	public String getName()
+	{
+		return name;
+	}
+
+	public boolean acceptReference(ResourceReference ref)
+	{
+		return !other.acceptReference(ref);
+	}
+
+	public boolean acceptOtherJavascript()
+	{
+		return !other.acceptOtherJavascript();
+	}
+
+	public boolean acceptOtherCss()
+	{
+		return !other.acceptOtherCss();
+	}
+
+}