You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@wicket.apache.org by jd...@apache.org on 2007/06/17 09:58:21 UTC

svn commit: r548018 - in /incubator/wicket/trunk/jdk-1.4/wicket/src/main/java/org/apache/wicket: ./ markup/ markup/loader/ settings/ util/watch/

Author: jdonnerstag
Date: Sun Jun 17 00:58:20 2007
New Revision: 548018

URL: http://svn.apache.org/viewvc?view=rev&rev=548018
Log:
Backported IMarkupLoader

Added:
    incubator/wicket/trunk/jdk-1.4/wicket/src/main/java/org/apache/wicket/markup/IMarkupCache.java   (with props)
    incubator/wicket/trunk/jdk-1.4/wicket/src/main/java/org/apache/wicket/markup/loader/
    incubator/wicket/trunk/jdk-1.4/wicket/src/main/java/org/apache/wicket/markup/loader/DefaultMarkupLoader.java   (with props)
    incubator/wicket/trunk/jdk-1.4/wicket/src/main/java/org/apache/wicket/markup/loader/IMarkupLoader.java   (with props)
    incubator/wicket/trunk/jdk-1.4/wicket/src/main/java/org/apache/wicket/markup/loader/InheritedMarkupMarkupLoader.java   (with props)
    incubator/wicket/trunk/jdk-1.4/wicket/src/main/java/org/apache/wicket/markup/loader/SimpleMarkupLoader.java   (with props)
Removed:
    incubator/wicket/trunk/jdk-1.4/wicket/src/main/java/org/apache/wicket/util/watch/Watcher.java
Modified:
    incubator/wicket/trunk/jdk-1.4/wicket/src/main/java/org/apache/wicket/Application.java
    incubator/wicket/trunk/jdk-1.4/wicket/src/main/java/org/apache/wicket/MarkupContainer.java
    incubator/wicket/trunk/jdk-1.4/wicket/src/main/java/org/apache/wicket/markup/DefaultMarkupCacheKeyProvider.java
    incubator/wicket/trunk/jdk-1.4/wicket/src/main/java/org/apache/wicket/markup/IMarkupCacheKeyProvider.java
    incubator/wicket/trunk/jdk-1.4/wicket/src/main/java/org/apache/wicket/markup/MarkupCache.java
    incubator/wicket/trunk/jdk-1.4/wicket/src/main/java/org/apache/wicket/markup/MarkupResourceData.java
    incubator/wicket/trunk/jdk-1.4/wicket/src/main/java/org/apache/wicket/markup/MarkupResourceStream.java
    incubator/wicket/trunk/jdk-1.4/wicket/src/main/java/org/apache/wicket/markup/MarkupStream.java
    incubator/wicket/trunk/jdk-1.4/wicket/src/main/java/org/apache/wicket/markup/MergedMarkup.java
    incubator/wicket/trunk/jdk-1.4/wicket/src/main/java/org/apache/wicket/settings/IMarkupSettings.java
    incubator/wicket/trunk/jdk-1.4/wicket/src/main/java/org/apache/wicket/settings/Settings.java
    incubator/wicket/trunk/jdk-1.4/wicket/src/main/java/org/apache/wicket/util/watch/ModificationWatcher.java

Modified: incubator/wicket/trunk/jdk-1.4/wicket/src/main/java/org/apache/wicket/Application.java
URL: http://svn.apache.org/viewvc/incubator/wicket/trunk/jdk-1.4/wicket/src/main/java/org/apache/wicket/Application.java?view=diff&rev=548018&r1=548017&r2=548018
==============================================================================
--- incubator/wicket/trunk/jdk-1.4/wicket/src/main/java/org/apache/wicket/Application.java (original)
+++ incubator/wicket/trunk/jdk-1.4/wicket/src/main/java/org/apache/wicket/Application.java Sun Jun 17 00:58:20 2007
@@ -31,7 +31,7 @@
 import org.apache.wicket.application.IComponentInstantiationListener;
 import org.apache.wicket.application.IComponentOnAfterRenderListener;
 import org.apache.wicket.application.IComponentOnBeforeRenderListener;
-import org.apache.wicket.markup.MarkupCache;
+import org.apache.wicket.markup.IMarkupCache;
 import org.apache.wicket.markup.html.image.resource.DefaultButtonImageResourceFactory;
 import org.apache.wicket.markup.parser.filter.RelativePathPrefixHandler;
 import org.apache.wicket.markup.parser.filter.WicketMessageTagHandler;
@@ -221,9 +221,6 @@
 	/** list of initializers. */
 	private List initializers = new ArrayList();
 
-	/** Markup cache for this application */
-	private final MarkupCache markupCache;
-
 	/** Application level meta data. */
 	private MetaDataEntry[] metaData;
 
@@ -254,9 +251,6 @@
 		// Create name from subclass
 		this.name = Classes.simpleName(getClass());
 
-		// Construct markup cache for this application
-		this.markupCache = new MarkupCache(this);
-
 		// Create shared resources repository
 		this.sharedResources = new SharedResources(this);
 
@@ -441,10 +435,11 @@
 	 * THIS METHOD IS NOT PART OF THE WICKET PUBLIC API. DO NOT USE IT.
 	 * 
 	 * @return The markup cache associated with the application
+	 * @deprecated please use {@link IMarkupSettings#getMarkupCache()} instead
 	 */
-	public final MarkupCache getMarkupCache()
+	public final IMarkupCache getMarkupCache()
 	{
-		return this.markupCache;
+		return getMarkupSettings().getMarkupCache();
 	}
 
 	/**

Modified: incubator/wicket/trunk/jdk-1.4/wicket/src/main/java/org/apache/wicket/MarkupContainer.java
URL: http://svn.apache.org/viewvc/incubator/wicket/trunk/jdk-1.4/wicket/src/main/java/org/apache/wicket/MarkupContainer.java?view=diff&rev=548018&r1=548017&r2=548018
==============================================================================
--- incubator/wicket/trunk/jdk-1.4/wicket/src/main/java/org/apache/wicket/MarkupContainer.java (original)
+++ incubator/wicket/trunk/jdk-1.4/wicket/src/main/java/org/apache/wicket/MarkupContainer.java Sun Jun 17 00:58:20 2007
@@ -328,7 +328,7 @@
 	{
 		try
 		{
-			return getApplication().getMarkupCache().getMarkupStream(this, throwException);
+			return getApplication().getMarkupSettings().getMarkupCache().getMarkupStream(this, false, throwException);
 		}
 		catch (MarkupException ex)
 		{
@@ -1479,6 +1479,6 @@
 	 */
 	final boolean hasAssociatedMarkup()
 	{
-		return getApplication().getMarkupCache().hasAssociatedMarkup(this);
+		return getApplication().getMarkupSettings().getMarkupCache().hasAssociatedMarkup(this);
 	}
 }

Modified: incubator/wicket/trunk/jdk-1.4/wicket/src/main/java/org/apache/wicket/markup/DefaultMarkupCacheKeyProvider.java
URL: http://svn.apache.org/viewvc/incubator/wicket/trunk/jdk-1.4/wicket/src/main/java/org/apache/wicket/markup/DefaultMarkupCacheKeyProvider.java?view=diff&rev=548018&r1=548017&r2=548018
==============================================================================
--- incubator/wicket/trunk/jdk-1.4/wicket/src/main/java/org/apache/wicket/markup/DefaultMarkupCacheKeyProvider.java (original)
+++ incubator/wicket/trunk/jdk-1.4/wicket/src/main/java/org/apache/wicket/markup/DefaultMarkupCacheKeyProvider.java Sun Jun 17 00:58:20 2007
@@ -48,14 +48,15 @@
 	 * @return Key that uniquely identifies any markup that might be associated
 	 *         with this markup container.
 	 */
-	public CharSequence getCacheKey(final MarkupContainer container, final Class clazz)
+	public String getCacheKey(final MarkupContainer container, final Class clazz)
 	{
 		final String classname = clazz.getName();
 		final Locale locale = container.getLocale();
+		// TODO until now getStyle() == style + variation
 		final String style = container.getStyle();
 		final String markupType = container.getMarkupType();
 
-		final AppendingStringBuffer buffer = new AppendingStringBuffer(classname.length() + 32);
+		final AppendingStringBuffer buffer = new AppendingStringBuffer(classname.length() + 64);
 		buffer.append(classname);
 
 		if (locale != null)
@@ -81,6 +82,6 @@
 		}
 
 		buffer.append(markupType);
-		return buffer;
+		return buffer.toString();
 	}
 }

Added: incubator/wicket/trunk/jdk-1.4/wicket/src/main/java/org/apache/wicket/markup/IMarkupCache.java
URL: http://svn.apache.org/viewvc/incubator/wicket/trunk/jdk-1.4/wicket/src/main/java/org/apache/wicket/markup/IMarkupCache.java?view=auto&rev=548018
==============================================================================
--- incubator/wicket/trunk/jdk-1.4/wicket/src/main/java/org/apache/wicket/markup/IMarkupCache.java (added)
+++ incubator/wicket/trunk/jdk-1.4/wicket/src/main/java/org/apache/wicket/markup/IMarkupCache.java Sun Jun 17 00:58:20 2007
@@ -0,0 +1,96 @@
+/*
+ * 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.markup;
+
+import org.apache.wicket.MarkupContainer;
+import org.apache.wicket.settings.IMarkupSettings;
+
+/**
+ * Each Wicket application has a single IMarkupCache associated with it (see
+ * {@link IMarkupSettings}). The markup cache is used by every Component to get
+ * its associated markup stream. Note that it is the markup caches
+ * responsibility to load the markup, if not yet done.
+ * 
+ * @author Juergen Donnerstag
+ */
+public interface IMarkupCache
+{
+	/**
+	 * Clear markup cache and force reload of all markup data
+	 */
+	void clear();
+
+	/**
+	 * Gets any (immutable) markup resource for the container or any of its
+	 * parent classes (markup inheritance)
+	 * 
+	 * @param container
+	 *            The original requesting markup container
+	 * @param clazz
+	 *            The class to get the associated markup for. If null, the
+	 *            container's class is used, but it can be a parent class of the
+	 *            container as well (markup inheritance)
+	 * @param enforceReload
+	 *            The cache will be ignored and all, including inherited markup
+	 *            files, will be reloaded. Whatever is in the cache, it will be
+	 *            ignored
+	 * @return Markup resource
+	 */
+	Markup getMarkup(final MarkupContainer container, final Class clazz, final boolean enforceReload);
+
+	/**
+	 * Gets a fresh markup stream that contains the (immutable) markup resource
+	 * for this class.
+	 * 
+	 * @param container
+	 *            The container the markup should be associated with
+	 * @param enforceReload
+	 *            The cache will be ignored and all, including inherited markup
+	 *            files, will be reloaded. Whatever is in the cache, it will be
+	 *            ignored
+	 * @param throwException
+	 *            If true, throw an exception, if markup could not be found
+	 * @return A stream of MarkupElement elements
+	 */
+	MarkupStream getMarkupStream(final MarkupContainer container, final boolean enforceReload,
+			final boolean throwException);
+
+	/**
+	 * Check if container has associated markup
+	 * 
+	 * @param container
+	 *            The container the markup should be associated with
+	 * @return True if this markup container has associated markup
+	 */
+	boolean hasAssociatedMarkup(final MarkupContainer container);
+
+	/**
+	 * Remove the markup associated with the cache key from the cache including
+	 * all dependent markups (markup inheritance)
+	 * 
+	 * @see MarkupResourceStream#getCacheKey()
+	 * 
+	 * @param cacheKey
+	 * @return The markup removed from the cache. Null, if nothing was found.
+	 */
+	Markup removeMarkup(final String cacheKey);
+
+	/**
+	 * @return the number of elements currently in the cache.
+	 */
+	int size();
+}
\ No newline at end of file

Propchange: incubator/wicket/trunk/jdk-1.4/wicket/src/main/java/org/apache/wicket/markup/IMarkupCache.java
------------------------------------------------------------------------------
    svn:eol-style = native

Modified: incubator/wicket/trunk/jdk-1.4/wicket/src/main/java/org/apache/wicket/markup/IMarkupCacheKeyProvider.java
URL: http://svn.apache.org/viewvc/incubator/wicket/trunk/jdk-1.4/wicket/src/main/java/org/apache/wicket/markup/IMarkupCacheKeyProvider.java?view=diff&rev=548018&r1=548017&r2=548018
==============================================================================
--- incubator/wicket/trunk/jdk-1.4/wicket/src/main/java/org/apache/wicket/markup/IMarkupCacheKeyProvider.java (original)
+++ incubator/wicket/trunk/jdk-1.4/wicket/src/main/java/org/apache/wicket/markup/IMarkupCacheKeyProvider.java Sun Jun 17 00:58:20 2007
@@ -39,5 +39,5 @@
 	 *            The container the markup should be associated with
 	 * @return A IResourceStream if the resource was found
 	 */
-	CharSequence getCacheKey(final MarkupContainer container, Class containerClass);
+	String getCacheKey(final MarkupContainer container, Class containerClass);
 }

Modified: incubator/wicket/trunk/jdk-1.4/wicket/src/main/java/org/apache/wicket/markup/MarkupCache.java
URL: http://svn.apache.org/viewvc/incubator/wicket/trunk/jdk-1.4/wicket/src/main/java/org/apache/wicket/markup/MarkupCache.java?view=diff&rev=548018&r1=548017&r2=548018
==============================================================================
--- incubator/wicket/trunk/jdk-1.4/wicket/src/main/java/org/apache/wicket/markup/MarkupCache.java (original)
+++ incubator/wicket/trunk/jdk-1.4/wicket/src/main/java/org/apache/wicket/markup/MarkupCache.java Sun Jun 17 00:58:20 2007
@@ -17,29 +17,40 @@
 package org.apache.wicket.markup;
 
 import java.io.IOException;
+import java.util.Iterator;
 import java.util.Map;
 
 import org.apache.wicket.Application;
 import org.apache.wicket.MarkupContainer;
 import org.apache.wicket.WicketRuntimeException;
+import org.apache.wicket.markup.loader.DefaultMarkupLoader;
+import org.apache.wicket.markup.loader.IMarkupLoader;
+import org.apache.wicket.settings.IMarkupSettings;
 import org.apache.wicket.util.concurrent.ConcurrentHashMap;
 import org.apache.wicket.util.listener.IChangeListener;
 import org.apache.wicket.util.resource.IResourceStream;
 import org.apache.wicket.util.resource.ResourceStreamNotFoundException;
+import org.apache.wicket.util.watch.IModifiable;
 import org.apache.wicket.util.watch.ModificationWatcher;
-import org.apache.wicket.util.watch.Watcher;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-
 /**
- * Load markup and cache it for fast retrieval. If markup file changes, it'll be
- * removed and subsequently reloaded when needed.
+ * This is Wicket's default IMarkupCache implementation. It will load the markup
+ * and cache it for fast retrieval.
+ * <p>
+ * If the application is in development mode and a markup file changes, it'll
+ * automatically be removed from the cache and reloaded when needed.
+ * <p>
+ * MarkupCache is registered with {@link IMarkupSettings} and thus can be
+ * replaced with a subclassed version.
+ * 
+ * @see IMarkupSettings
  * 
  * @author Jonathan Locke
  * @author Juergen Donnerstag
  */
-public class MarkupCache
+public class MarkupCache implements IMarkupCache
 {
 	/** Log for reporting. */
 	private static final Logger log = LoggerFactory.getLogger(MarkupCache.class);
@@ -47,13 +58,16 @@
 	/** Map of markup tags by class (exactly what is in the file). */
 	private final Map markupCache = new ConcurrentHashMap();
 
-	/**
-	 * Markup inheritance requires that merged markup gets re-merged either
-	 * AFTER the base markup or the derived markup has been reloaded.
-	 */
-	private final Watcher afterLoadListeners = new Watcher();
+	/** The markup cache key provider used by MarkupCache */
+	private IMarkupCacheKeyProvider markupCacheKeyProvider;
+
+	/** The markup resource stream provider used by MarkupCache */
+	private IMarkupResourceStreamProvider markupResourceStreamProvider;
+
+	/** The markup loader used by MarkupCache */
+	private IMarkupLoader markupLoader;
 
-	/** The Wicket application */
+	/** The application object */
 	private final Application application;
 
 	/**
@@ -61,45 +75,109 @@
 	 * 
 	 * @param application
 	 */
-	public MarkupCache(final Application application)
+	public MarkupCache()
 	{
-		this.application = application;
+		this.application = Application.get();
 	}
 
 	/**
-	 * Clear markup cache and force reload of all markup data
+	 * @see org.apache.wicket.markup.IMarkupCache#clear()
 	 */
-	public void clear()
+	public final void clear()
 	{
-		this.afterLoadListeners.clear();
 		this.markupCache.clear();
 	}
 
 	/**
-	 * Gets a fresh markup stream that contains the (immutable) markup resource
-	 * for this class.
-	 * 
-	 * @param container
-	 *            The container the markup should be associated with
-	 * @return A stream of MarkupElement elements
+	 * @see org.apache.wicket.markup.IMarkupCache#removeMarkup(java.lang.String)
 	 */
-	public final MarkupStream getMarkupStream(final MarkupContainer container)
+	public final Markup removeMarkup(final String cacheKey)
 	{
-		return getMarkupStream(container, true);
+		if (cacheKey == null)
+		{
+			throw new IllegalArgumentException("Parameter 'cacheKey' must not be null");
+		}
+
+		if (log.isDebugEnabled())
+		{
+			log.debug("Remove from cache: cacheKey=" + cacheKey);
+		}
+
+		// Remove the markup and any other markup which depends on it
+		// (inheritance)
+		Markup markup = (Markup)markupCache.remove(cacheKey);
+		if (markup != null)
+		{
+			// In practice markup inheritance has probably not more than 3 or 4
+			// levels. And since markup reloading is only enabled in development
+			// mode, this max 4 iterations of the outer loop shouldn't be a
+			// problem.
+			int count;
+			do
+			{
+				count = 0;
+
+				// If a base markup file has been removed from the cache, than
+				// the derived markup should be removed as well.
+				Iterator iter = markupCache.values().iterator();
+				while (iter.hasNext())
+				{
+					Markup cacheMarkup = (Markup)iter.next();
+					MarkupResourceData resourceData = cacheMarkup.getMarkupResourceData()
+							.getBaseMarkupResourceData();
+					if (resourceData != null)
+					{
+						String baseCacheKey = resourceData.getResource().getCacheKey();
+						if (markupCache.get(baseCacheKey) == null)
+						{
+							if (log.isDebugEnabled())
+							{
+								log.debug("Remove from cache: cacheKey=" +
+										cacheMarkup.getMarkupResourceData().getResource()
+												.getCacheKey());
+							}
+
+							iter.remove();
+							count++;
+						}
+					}
+				}
+			}
+			while (count > 0);
+
+			// And now remove all watcher entries associated with markup
+			// resources no longer in the cache. Note that you can not use
+			// Application.get() since removeMarkup() will be call from a
+			// ModificationWatcher thread which has no associated Application.
+			final ModificationWatcher watcher = application.getResourceSettings()
+					.getResourceWatcher(true);
+			if (watcher != null)
+			{
+				Iterator iter = watcher.getEntries().iterator();
+				while (iter.hasNext())
+				{
+					IModifiable modifiable = (IModifiable)iter.next();
+					if (modifiable instanceof MarkupResourceStream)
+					{
+						MarkupResourceStream resourceStream = (MarkupResourceStream)modifiable;
+						String resourceCacheKey = resourceStream.getCacheKey();
+						if (markupCache.containsKey(resourceCacheKey) == false)
+						{
+							iter.remove();
+						}
+					}
+				}
+			}
+		}
+		return markup;
 	}
 
 	/**
-	 * Gets a fresh markup stream that contains the (immutable) markup resource
-	 * for this class.
-	 * 
-	 * @param container
-	 *            The container the markup should be associated with
-	 * @param throwException
-	 *            If true, throw an exception, if markup could not be found
-	 * @return A stream of MarkupElement elements
+	 * @see org.apache.wicket.markup.IMarkupCache#getMarkupStream(org.apache.wicket.MarkupContainer,
+	 *      boolean, boolean)
 	 */
 	public final MarkupStream getMarkupStream(final MarkupContainer container,
-			final boolean throwException)
+			final boolean enforceReload, final boolean throwException)
 	{
 		if (container == null)
 		{
@@ -107,7 +185,7 @@
 		}
 
 		// Look for associated markup
-		final Markup markup = getMarkup(container, container.getClass());
+		final Markup markup = getMarkup(container, container.getClass(), false);
 
 		// If we found markup for this container
 		if (markup != Markup.NO_MARKUP)
@@ -118,245 +196,201 @@
 		if (throwException == true)
 		{
 			// throw exception since there is no associated markup
-			throw new MarkupNotFoundException(
-					"Markup not found. Component class: "
-							+ container.getClass().getName()
-							+ " Enable debug messages for org.apache.wicket.util.resource to get a list of all filenames tried");
+			throw new MarkupNotFoundException("Markup not found. Component class: " +
+					container.getClass().getName() +
+					" Enable debug messages for org.apache.wicket.util.resource to get a list of all filenames tried");
 		}
 
 		return null;
 	}
 
 	/**
-	 * Check if container has associated markup
-	 * 
-	 * @param container
-	 *            The container the markup should be associated with
-	 * @return True if this markup container has associated markup
+	 * @see org.apache.wicket.markup.IMarkupCache#hasAssociatedMarkup(org.apache.wicket.MarkupContainer)
 	 */
 	public final boolean hasAssociatedMarkup(final MarkupContainer container)
 	{
-		return getMarkup(container, container.getClass()) != Markup.NO_MARKUP;
+		return getMarkup(container, container.getClass(), false) != Markup.NO_MARKUP;
 	}
 
 	/**
-	 * @return the number of elements currently in the cache.
+	 * @see org.apache.wicket.markup.IMarkupCache#size()
 	 */
-	public int size()
+	public final int size()
 	{
 		return markupCache.size();
 	}
 
 	/**
-	 * The markup has just been loaded and now we check if markup inheritance
-	 * applies, which is if <wicket:extend> is found in the markup. If yes, than
-	 * load the base markups and merge the markup elements to create an updated
-	 * (merged) list of markup elements.
+	 * THIS IS NOT PART OF WICKET'S PUBLIC API. DO NOT USE IT.
 	 * 
-	 * @param container
-	 *            The original requesting markup container
-	 * @param markup
-	 *            The markup to checked for inheritance
-	 * @return A markup object with the the base markup elements resolved.
+	 * I still don't like this method being part of the API but I didn't find a
+	 * suitable other solution.
+	 * 
+	 * @see org.apache.wicket.markup.IMarkupCache#getMarkup(org.apache.wicket.MarkupContainer,
+	 *      java.lang.Class, boolean)
 	 */
-	private Markup checkForMarkupInheritance(final MarkupContainer container, final Markup markup)
+	public final Markup getMarkup(final MarkupContainer container, final Class clazz,
+			final boolean enforceReload)
 	{
-		// Check if markup contains <wicket:extend> which tells us that
-		// we need to read the inherited markup as well.
-		int extendIndex = requiresBaseMarkup(markup);
-		if (extendIndex == -1)
+		Class containerClass = clazz;
+		if (clazz == null)
 		{
-			// return a MarkupStream for the markup
-			return markup;
+			containerClass = container.getClass();
 		}
-
-		// get the base markup
-		final Markup baseMarkup = getMarkup(container, markup.getMarkupResourceData().getResource().getMarkupClass()
-				.getSuperclass());
-
-		if (baseMarkup == Markup.NO_MARKUP)
+		else
 		{
-			throw new MarkupNotFoundException(
-					"Parent markup of inherited markup not found. Component class: "
-							+ markup.getMarkupResourceData().getResource().getContainerInfo().getContainerClass().getName()
-							+ " Enable debug messages for org.apache.wicket.util.resource.Resource to get a list of all filenames tried.");
+			if (!clazz.isAssignableFrom(container.getClass()))
+			{
+				throw new WicketRuntimeException("Parameter clazz must be instance of container");
+			}
 		}
 
-		final CharSequence key = markup.getMarkupResourceData().getResource().getCacheKey();
-		if (key != null)
+		// Get the cache key to be associated with the markup resource stream
+		final String cacheKey = getMarkupCacheKeyProvider(container).getCacheKey(container, clazz);
+
+		// Is the markup already in the cache?
+		Markup markup = (enforceReload == false ? getMarkupFromCache(cacheKey, container) : null);
+		if (markup == null)
 		{
-			// register an after-load listener for base markup. The listener
-			// implementation will remove the derived markup which must be
-			// merged with the base markup
-			afterLoadListeners.add(baseMarkup.getMarkupResourceData().getResource(), new IChangeListener()
+			if (log.isDebugEnabled())
 			{
-				/**
-				 * Make sure there is only one listener per derived markup
-				 * 
-				 * @see java.lang.Object#equals(java.lang.Object)
-				 */
-				public boolean equals(Object obj)
-				{
-					return true;
-				}
+				log.debug("Load markup: cacheKey=" + cacheKey);
+			}
+
+			// Who is going to provide the markup resource stream?
+			// And ask the provider to locate the markup resource stream
+			final IResourceStream resourceStream = getMarkupResourceStreamProvider(container)
+					.getMarkupResourceStream(container, containerClass);
 
-				/**
-				 * Make sure there is only one listener per derived markup
-				 * 
-				 * @see java.lang.Object#hashCode()
-				 */
-				public int hashCode()
+			// Found markup?
+			if (resourceStream != null)
+			{
+				final MarkupResourceStream markupResourceStream;
+				if (resourceStream instanceof MarkupResourceStream)
 				{
-					return key.hashCode();
+					markupResourceStream = (MarkupResourceStream)resourceStream;
 				}
-
-				public void onChange()
+				else
 				{
-					if (log.isDebugEnabled())
-					{
-						log.debug("Remove derived markup from cache: " + markup.getMarkupResourceData().getResource());
-					}
-					removeMarkup(markup.getMarkupResourceData().getResource());
+					markupResourceStream = new MarkupResourceStream(resourceStream,
+							new ContainerInfo(container), containerClass);
 				}
-			});
-		}
 
-		// Merge base and derived markup
-		Markup mergedMarkup = new MergedMarkup(markup, baseMarkup, extendIndex);
-		return mergedMarkup;
+				markupResourceStream.setCacheKey(cacheKey);
+
+				// load the markup and watch for changes
+				markup = loadMarkupAndWatchForChanges(container, markupResourceStream,
+						enforceReload);
+			}
+			else
+			{
+				markup = onMarkupNotFound(cacheKey, container);
+			}
+		}
+		return markup;
 	}
 
 	/**
-	 * Gets any (immutable) markup resource for the container or any of its
-	 * parent classes (markup inheritance)
+	 * Will be called if the markup was not in the cache yet but could not be
+	 * found either.
+	 * <p>
+	 * Subclasses may change the default implementation. E.g. they might choose
+	 * not update the cache to enforce reloading of any markup not found. This
+	 * might be useful in very dynamic environments.
 	 * 
+	 * @param cacheKey
 	 * @param container
-	 *            The original requesting markup container
-	 * @param clazz
-	 *            The class to get the associated markup for. If null, the
-	 *            container's class is used, but it can be a parent class of the
-	 *            container as well (markup inheritance)
-	 * @return Markup resource
+	 * @return Markup.NO_MARKUP
 	 */
-	private final Markup getMarkup(final MarkupContainer container, final Class clazz)
+	protected Markup onMarkupNotFound(final String cacheKey, final MarkupContainer container)
 	{
-		Class containerClass = clazz;
-		if (clazz == null)
-		{
-			containerClass = container.getClass();
-		}
-		else
+		if (log.isDebugEnabled())
 		{
-			if (!clazz.isAssignableFrom(container.getClass()))
-			{
-				throw new WicketRuntimeException("Parameter clazz must be instance of container");
-			}
+			log.debug("Markup not found: " + cacheKey);
 		}
 
-		// Get the cache key to be associated with the markup resource stream
-		final IMarkupCacheKeyProvider markupCacheKeyProvider = getMarkupCacheKeyProvider(container);
-		final CharSequence cacheKey = markupCacheKeyProvider.getCacheKey(container, clazz);
+		// flag markup as non-existent
+		return putIntoCache(cacheKey, Markup.NO_MARKUP);
+	}
 
-		// Markup already in the cache? If cacheKey == null, than don't cache
-		// the markup resource stream
-		Markup markup = null;
+	/**
+	 * Put the markup into the cache if cacheKey is not null and the cache does
+	 * not yet contain the cacheKey. Return the markup stored in the cache if
+	 * cacheKey is present already.
+	 * 
+	 * @param cacheKey
+	 *            If null, than ignore the cache
+	 * @param markup
+	 * @return markup The markup provided, except if the cacheKey already
+	 *         existed in the cache, than the markup from the cache is provided.
+	 */
+	protected Markup putIntoCache(final String cacheKey, Markup markup)
+	{
 		if (cacheKey != null)
 		{
-			markup = (Markup)markupCache.get(cacheKey);
-		}
-
-		// Must Markup be loaded?
-		if (markup == null)
-		{
-			synchronized (markupCache)
+			if (markupCache.containsKey(cacheKey) == false)
 			{
-				if (cacheKey != null)
-				{
-					markup = (Markup)markupCache.get(cacheKey);
-				}
-
-				// Must Markup be loaded?
-				if (markup == null)
-				{
-					// Who is going to provide the markup resource stream?
-					final IMarkupResourceStreamProvider markupResourceStreamProvider = getMarkupResourceStreamProvider(container);
-
-					// Ask the provider to locate the markup resource stream
-					final IResourceStream resourceStream = markupResourceStreamProvider
-							.getMarkupResourceStream(container, containerClass);
-
-					// Found markup?
-					if (resourceStream != null)
-					{
-						final MarkupResourceStream markupResourceStream;
-						if (resourceStream instanceof MarkupResourceStream)
-						{
-							markupResourceStream = (MarkupResourceStream)resourceStream;
-						}
-						else
-						{
-							markupResourceStream = new MarkupResourceStream(resourceStream,
-									new ContainerInfo(container), containerClass);
-						}
-
-						markupResourceStream.setCacheKey(cacheKey);
-
-						// load the markup and watch for changes
-						markup = loadMarkupAndWatchForChanges(container, markupResourceStream);
-					}
-					else
-					{
-						// flag markup as non-existent (as opposed to null,
-						// which might mean that it's simply not loaded into
-						// the cache)
-						markup = Markup.NO_MARKUP;
-
-						// Save any markup list (or absence of one) for next
-						// time
-						if (cacheKey != null)
-						{
-							markupCache.put(cacheKey, markup);
-						}
-					}
-				}
+				markupCache.put(cacheKey, markup);
+			}
+			else
+			{
+				// We don't lock the cache while loading a markup. Thus it may
+				// happen that the very same markup gets loaded twice (the first
+				// markup being loaded, but not yet in the cache, and another
+				// request requesting the very same markup). Since markup
+				// loading in avg takes less than 100ms, it is not really an
+				// issue. For consistency reasons however, we should always use
+				// the markup loaded first which is why it gets returned.
+				markup = (Markup)markupCache.get(cacheKey);
 			}
 		}
 		return markup;
 	}
 
 	/**
+	 * Wicket's default implementation just uses the cacheKey to retrieve the
+	 * markup from the cache. More sofisticated implementations may call a
+	 * container method to e.g. ignore the cached markup under certain
+	 * situations.
+	 * 
+	 * @param cacheKey
+	 *            If null, than the cache will be ignored
+	 * @param container
+	 * @return null, if not found or to enforce reloading the markup
+	 */
+	protected Markup getMarkupFromCache(final CharSequence cacheKey, final MarkupContainer container)
+	{
+		if (cacheKey != null)
+		{
+			return (Markup)markupCache.get(cacheKey);
+		}
+		return null;
+	}
+
+	/**
 	 * Loads markup from a resource stream.
 	 * 
 	 * @param container
 	 *            The original requesting markup container
 	 * @param markupResourceStream
 	 *            The markup resource stream to load
+	 * @param enforceReload
+	 *            The cache will be ignored and all, including inherited markup
+	 *            files, will be reloaded. Whatever is in the cache, it will be
+	 *            ignored
 	 * @return The markup
 	 */
 	private final Markup loadMarkup(final MarkupContainer container,
-			final MarkupResourceStream markupResourceStream)
+			final MarkupResourceStream markupResourceStream, final boolean enforceReload)
 	{
-		CharSequence cacheKey = markupResourceStream.getCacheKey();
+		String cacheKey = markupResourceStream.getCacheKey();
 		try
 		{
-			// read and parse the markup
-			Markup markup = application.getMarkupSettings().getMarkupParserFactory()
-					.newMarkupParser(markupResourceStream).parse();
-
-			// Check for markup inheritance. If it contains <wicket:extend>
-			// the two markups get merged.
-			markup = checkForMarkupInheritance(container, markup);
+			Markup markup = getMarkupLoader().loadMarkup(container, markupResourceStream, null,
+					enforceReload);
 
-			// add the markup to the cache
-			if (cacheKey != null)
-			{
-				markupCache.put(cacheKey, markup);
-			}
-
-			// trigger all listeners registered on the markup just loaded
-			afterLoadListeners.notifyListeners(markupResourceStream);
-
-			return markup;
+			// add the markup to the cache.
+			return putIntoCache(cacheKey, markup);
 		}
 		catch (ResourceStreamNotFoundException e)
 		{
@@ -368,13 +402,9 @@
 		}
 
 		// In case of an error, remove the cache entry
-		synchronized (markupCache)
+		if (cacheKey != null)
 		{
-			if (cacheKey != null)
-			{
-				markupCache.remove(cacheKey);
-				afterLoadListeners.remove(markupResourceStream);
-			}
+			removeMarkup(cacheKey);
 		}
 
 		return Markup.NO_MARKUP;
@@ -390,15 +420,20 @@
 	 *            The original requesting markup container
 	 * @param markupResourceStream
 	 *            The markup stream to load and begin to watch
+	 * @param enforceReload
+	 *            The cache will be ignored and all, including inherited markup
+	 *            files, will be reloaded. Whatever is in the cache, it will be
+	 *            ignored
 	 * @return The markup in the stream
 	 */
 	private final Markup loadMarkupAndWatchForChanges(final MarkupContainer container,
-			final MarkupResourceStream markupResourceStream)
+			final MarkupResourceStream markupResourceStream, final boolean enforceReload)
 	{
-		if (markupResourceStream.getCacheKey() != null)
+		final String cacheKey = markupResourceStream.getCacheKey();
+		if (cacheKey != null)
 		{
 			// Watch file in the future
-			final ModificationWatcher watcher = application.getResourceSettings()
+			final ModificationWatcher watcher = Application.get().getResourceSettings()
 					.getResourceWatcher(true);
 			if (watcher != null)
 			{
@@ -412,9 +447,9 @@
 						}
 
 						// Remove the markup from the cache. It will be reloaded
-						// next time it the markup is requested.
-						removeMarkup(markupResourceStream);
+						// next time when the markup is requested.
 						watcher.remove(markupResourceStream);
+						removeMarkup(cacheKey);
 					}
 				});
 			}
@@ -424,86 +459,63 @@
 		{
 			log.debug("Loading markup from " + markupResourceStream);
 		}
-		return loadMarkup(container, markupResourceStream);
+		return loadMarkup(container, markupResourceStream, enforceReload);
 	}
 
 	/**
-	 * Remove the markup from the cache and trigger all associated listeners
+	 * Get the markup cache key provider to be used
 	 * 
-	 * @param markupResourceStream
-	 *            The resource stream
+	 * @param container
+	 *            The MarkupContainer requesting the markup resource stream
+	 * @return IMarkupResourceStreamProvider
 	 */
-	private void removeMarkup(final MarkupResourceStream markupResourceStream)
+	public IMarkupCacheKeyProvider getMarkupCacheKeyProvider(final MarkupContainer container)
 	{
-		CharSequence cacheKey = markupResourceStream.getCacheKey();
-		if (cacheKey != null)
+		if (container instanceof IMarkupCacheKeyProvider)
 		{
-			markupCache.remove(cacheKey);
-			// trigger all listeners registered on the markup that is removed
-			afterLoadListeners.notifyListeners(markupResourceStream);
-			afterLoadListeners.remove(markupResourceStream);
+			return (IMarkupCacheKeyProvider)container;
 		}
-	}
 
-	/**
-	 * Check if markup contains &lt;wicket:extend&gt; which tells us that we
-	 * need to read the inherited markup as well. &lt;wicket:extend&gt; MUST BE
-	 * the first wicket tag in the markup. Skip raw markup
-	 * 
-	 * @param markup
-	 * @return == 0, if no wicket:extend was found
-	 */
-	private int requiresBaseMarkup(final Markup markup)
-	{
-		for (int i = 0; i < markup.size(); i++)
+		if (this.markupCacheKeyProvider == null)
 		{
-			MarkupElement elem = (MarkupElement)markup.get(i);
-			if (elem instanceof WicketTag)
-			{
-				WicketTag wtag = (WicketTag)elem;
-				if (wtag.isExtendTag())
-				{
-					// Ok, inheritance is on and we must get the
-					// inherited markup as well.
-					return i;
-				}
-			}
+			this.markupCacheKeyProvider = new DefaultMarkupCacheKeyProvider();
 		}
-		return -1;
+		return this.markupCacheKeyProvider;
 	}
 
 	/**
-	 * Determine the markup cache key provider to be used
+	 * Get the markup resource stream provider to be used
 	 * 
 	 * @param container
 	 *            The MarkupContainer requesting the markup resource stream
 	 * @return IMarkupResourceStreamProvider
 	 */
-	protected IMarkupCacheKeyProvider getMarkupCacheKeyProvider(final MarkupContainer container)
+	protected IMarkupResourceStreamProvider getMarkupResourceStreamProvider(
+			final MarkupContainer container)
 	{
-		if (container instanceof IMarkupCacheKeyProvider)
+		if (container instanceof IMarkupResourceStreamProvider)
 		{
-			return (IMarkupCacheKeyProvider)container;
+			return (IMarkupResourceStreamProvider)container;
 		}
 
-		return new DefaultMarkupCacheKeyProvider();
+		if (this.markupResourceStreamProvider == null)
+		{
+			this.markupResourceStreamProvider = new DefaultMarkupResourceStreamProvider();
+		}
+		return this.markupResourceStreamProvider;
 	}
 
 	/**
-	 * Determine the markup resource stream provider to be used
+	 * In case there is a need to extend the default chain of MarkupLoaders
 	 * 
-	 * @param container
-	 *            The MarkupContainer requesting the markup resource stream
-	 * @return IMarkupResourceStreamProvider
+	 * @return MarkupLoader
 	 */
-	protected IMarkupResourceStreamProvider getMarkupResourceStreamProvider(
-			final MarkupContainer container)
+	protected IMarkupLoader getMarkupLoader()
 	{
-		if (container instanceof IMarkupResourceStreamProvider)
+		if (markupLoader == null)
 		{
-			return (IMarkupResourceStreamProvider)container;
+			markupLoader = new DefaultMarkupLoader();
 		}
-
-		return new DefaultMarkupResourceStreamProvider();
+		return markupLoader;
 	}
 }

Modified: incubator/wicket/trunk/jdk-1.4/wicket/src/main/java/org/apache/wicket/markup/MarkupResourceData.java
URL: http://svn.apache.org/viewvc/incubator/wicket/trunk/jdk-1.4/wicket/src/main/java/org/apache/wicket/markup/MarkupResourceData.java?view=diff&rev=548018&r1=548017&r2=548018
==============================================================================
--- incubator/wicket/trunk/jdk-1.4/wicket/src/main/java/org/apache/wicket/markup/MarkupResourceData.java (original)
+++ incubator/wicket/trunk/jdk-1.4/wicket/src/main/java/org/apache/wicket/markup/MarkupResourceData.java Sun Jun 17 00:58:20 2007
@@ -37,9 +37,12 @@
 	/** Placeholder that indicates no markup */
 	public static final MarkupResourceData NO_MARKUP_RESOURCE_DATA = new MarkupResourceData();
 
-	/** The markup's resource stream for diagnostic purposes */
+	/** The markup's resource stream */
 	private MarkupResourceStream resource;
 
+	/** In case of the inherited markup, the base markup's resource stream */
+	private MarkupResourceData baseMarkupResourceData;
+
 	/** If found in the markup, the <?xml ...?> string */
 	private String xmlDeclaration;
 
@@ -80,7 +83,7 @@
 	 * 
 	 * @return The resource where this markup came from
 	 */
-	MarkupResourceStream getResource()
+	public MarkupResourceStream getResource()
 	{
 		return resource;
 	}
@@ -125,7 +128,7 @@
 	{
 		return wicketId;
 	}
-	
+
 	/**
 	 * Sets encoding.
 	 * 
@@ -175,5 +178,26 @@
 	final void setResource(final MarkupResourceStream resource)
 	{
 		this.resource = resource;
+	}
+
+	/**
+	 * Get the resource stream containing the base markup (markup inheritance)
+	 * 
+	 * @return baseMarkupResource Null, if not base markup
+	 */
+	public MarkupResourceData getBaseMarkupResourceData()
+	{
+		return this.baseMarkupResourceData;
+	}
+
+	/**
+	 * In case of markup inheritance, the base markup resource.
+	 * 
+	 * @param baseMarkupResourceData
+	 *            The base markup resource
+	 */
+	public void setBaseMarkupResourceData(MarkupResourceData baseMarkupResourceData)
+	{
+		this.baseMarkupResourceData = baseMarkupResourceData;
 	}
 }

Modified: incubator/wicket/trunk/jdk-1.4/wicket/src/main/java/org/apache/wicket/markup/MarkupResourceStream.java
URL: http://svn.apache.org/viewvc/incubator/wicket/trunk/jdk-1.4/wicket/src/main/java/org/apache/wicket/markup/MarkupResourceStream.java?view=diff&rev=548018&r1=548017&r2=548018
==============================================================================
--- incubator/wicket/trunk/jdk-1.4/wicket/src/main/java/org/apache/wicket/markup/MarkupResourceStream.java (original)
+++ incubator/wicket/trunk/jdk-1.4/wicket/src/main/java/org/apache/wicket/markup/MarkupResourceStream.java Sun Jun 17 00:58:20 2007
@@ -51,7 +51,7 @@
 	private final Class markupClass;
 
 	/** The key used to cache the markup resource stream */
-	private CharSequence cacheKey;
+	private String cacheKey;
 
 	/**
 	 * Construct.
@@ -178,7 +178,7 @@
 	 * Gets cacheKey.
 	 * @return cacheKey
 	 */
-	public final CharSequence getCacheKey()
+	public final String getCacheKey()
 	{
 		return cacheKey;
 	}
@@ -187,7 +187,7 @@
 	 * Set the cache key
 	 * @param cacheKey
 	 */
-	public final void setCacheKey(final CharSequence cacheKey)
+	public final void setCacheKey(final String cacheKey)
 	{
 		this.cacheKey = cacheKey;
 	}

Modified: incubator/wicket/trunk/jdk-1.4/wicket/src/main/java/org/apache/wicket/markup/MarkupStream.java
URL: http://svn.apache.org/viewvc/incubator/wicket/trunk/jdk-1.4/wicket/src/main/java/org/apache/wicket/markup/MarkupStream.java?view=diff&rev=548018&r1=548017&r2=548018
==============================================================================
--- incubator/wicket/trunk/jdk-1.4/wicket/src/main/java/org/apache/wicket/markup/MarkupStream.java (original)
+++ incubator/wicket/trunk/jdk-1.4/wicket/src/main/java/org/apache/wicket/markup/MarkupStream.java Sun Jun 17 00:58:20 2007
@@ -74,15 +74,6 @@
 	}
 
 	/**
-	 * DO NOT YOU THIS CONSTRUCTOR. IT WILL MOST LIKELY BE REPLACED IN THE NEAR
-	 * FUTURE.
-	 */
-	protected MarkupStream()
-	{
-		this.markup = null;
-	}
-
-	/**
 	 * @return True if current markup element is a close tag
 	 */
 	public boolean atCloseTag()

Modified: incubator/wicket/trunk/jdk-1.4/wicket/src/main/java/org/apache/wicket/markup/MergedMarkup.java
URL: http://svn.apache.org/viewvc/incubator/wicket/trunk/jdk-1.4/wicket/src/main/java/org/apache/wicket/markup/MergedMarkup.java?view=diff&rev=548018&r1=548017&r2=548018
==============================================================================
--- incubator/wicket/trunk/jdk-1.4/wicket/src/main/java/org/apache/wicket/markup/MergedMarkup.java (original)
+++ incubator/wicket/trunk/jdk-1.4/wicket/src/main/java/org/apache/wicket/markup/MergedMarkup.java Sun Jun 17 00:58:20 2007
@@ -35,13 +35,13 @@
  * The markup resource file, which is associated with the markup, will be the
  * resource of the requested markup file. The base markup resources are not.
  * <p>
- * Base Markup must have a &lt;wicket:hild/&gt; tag which the position where the
- * derived markup is inserted. From the derived markup all tags in between
- * &lt;wicket:extend&gt; and &lt;/wicket:extend&gt; will be inserted.
+ * Base Markup must have a &lt;wicket:child/&gt; tag at the position where the
+ * derived markup should be inserted. From the derived markup all tags in
+ * between &lt;wicket:extend&gt; and &lt;/wicket:extend&gt; will be inserted.
  * <p>
- * In addition, all &lt;wicket:head> regions are copied as well as the body
- * onLoad attribute. This allows to develop completely self-contained plug &
- * play components including javascript etc.
+ * In addition, all &lt;wicket:head> regions are copied as well. This allows to
+ * develop completely self-contained plug & play components including javascript
+ * etc.
  * 
  * @author Juergen Donnerstag
  */
@@ -59,22 +59,27 @@
 	 * @param extendIndex
 	 *            Index where <wicket:extend> has been found
 	 */
-	MergedMarkup(final Markup markup, final Markup baseMarkup, int extendIndex)
+	public MergedMarkup(final Markup markup, final Markup baseMarkup, int extendIndex)
 	{
 		super(new MarkupResourceData());
-		
+
 		// Copy settings from derived markup
 		getMarkupResourceData().setResource(markup.getMarkupResourceData().getResource());
-		getMarkupResourceData().setXmlDeclaration(markup.getMarkupResourceData().getXmlDeclaration());
+		getMarkupResourceData().setXmlDeclaration(
+				markup.getMarkupResourceData().getXmlDeclaration());
 		getMarkupResourceData().setEncoding(markup.getMarkupResourceData().getEncoding());
-		getMarkupResourceData().setWicketNamespace(markup.getMarkupResourceData().getWicketNamespace());
+		getMarkupResourceData().setWicketNamespace(
+				markup.getMarkupResourceData().getWicketNamespace());
+		getMarkupResourceData().setBaseMarkupResourceData(baseMarkup.getMarkupResourceData());
 
 		if (log.isDebugEnabled())
 		{
-			String derivedResource = Strings.afterLast(markup.getMarkupResourceData().getResource().toString(), '/');
-			String baseResource = Strings.afterLast(baseMarkup.getMarkupResourceData().getResource().toString(), '/');
-			log.debug("Merge markup: derived markup: " + derivedResource + "; base markup: "
-					+ baseResource);
+			String derivedResource = Strings.afterLast(markup.getMarkupResourceData().getResource()
+					.toString(), '/');
+			String baseResource = Strings.afterLast(baseMarkup.getMarkupResourceData()
+					.getResource().toString(), '/');
+			log.debug("Merge markup: derived markup: " + derivedResource + "; base markup: " +
+					baseResource);
 		}
 
 		// Merge derived and base markup
@@ -123,20 +128,24 @@
 
 			// Make sure all tags of the base markup remember where they are
 			// from
-			if ((baseMarkup.getMarkupResourceData().getResource() != null) && (tag.getMarkupClass() == null))
+			if ((baseMarkup.getMarkupResourceData().getResource() != null) &&
+					(tag.getMarkupClass() == null))
 			{
-				tag.setMarkupClass(baseMarkup.getMarkupResourceData().getResource().getMarkupClass());
+				tag.setMarkupClass(baseMarkup.getMarkupResourceData().getResource()
+						.getMarkupClass());
 			}
 
 			if (element instanceof WicketTag)
 			{
 				WicketTag wtag = (WicketTag)element;
 
-				// Found org.apache.wicket.child in base markup. In case of 3+ level
+				// Found org.apache.wicket.child in base markup. In case of 3+
+				// level
 				// inheritance make sure the child tag is not from one of the
 				// deeper levels
-				if (wtag.isChildTag()
-						&& (tag.getMarkupClass() == baseMarkup.getMarkupResourceData().getResource().getMarkupClass()))
+				if (wtag.isChildTag() &&
+						(tag.getMarkupClass() == baseMarkup.getMarkupResourceData().getResource()
+								.getMarkupClass()))
 				{
 					if (wtag.isOpenClose())
 					{
@@ -144,7 +153,8 @@
 						childTag = wtag;
 						WicketTag childOpenTag = (WicketTag)wtag.mutable();
 						childOpenTag.getXmlTag().setType(XmlTag.OPEN);
-						childOpenTag.setMarkupClass(baseMarkup.getMarkupResourceData().getResource().getMarkupClass());
+						childOpenTag.setMarkupClass(baseMarkup.getMarkupResourceData()
+								.getResource().getMarkupClass());
 						addMarkupElement(childOpenTag);
 						break;
 					}
@@ -156,8 +166,8 @@
 					}
 					else
 					{
-						throw new WicketRuntimeException("Did not expect a </wicket:child> tag in "
-								+ baseMarkup.toString());
+						throw new WicketRuntimeException(
+								"Did not expect a </wicket:child> tag in " + baseMarkup.toString());
 					}
 				}
 
@@ -195,8 +205,8 @@
 			if (wicketHeadProcessed == false)
 			{
 				// if <head> in base markup
-				if ((tag.isClose() && TagUtils.isHeadTag(tag))
-						|| (tag.isOpen() && TagUtils.isBodyTag(tag)))
+				if ((tag.isClose() && TagUtils.isHeadTag(tag)) ||
+						(tag.isOpen() && TagUtils.isBodyTag(tag)))
 				{
 					wicketHeadProcessed = true;
 
@@ -211,8 +221,8 @@
 
 		if (baseIndex == baseMarkup.size())
 		{
-			throw new WicketRuntimeException("Expected to find <wicket:child/> in base markup: "
-					+ baseMarkup.toString());
+			throw new WicketRuntimeException("Expected to find <wicket:child/> in base markup: " +
+					baseMarkup.toString());
 		}
 
 		// Now append all elements from the derived markup starting with
@@ -250,22 +260,23 @@
 					if (tag.isChildTag() && tag.isClose())
 					{
 						// Ok, skipped the childs content
-						tag.setMarkupClass(baseMarkup.getMarkupResourceData().getResource().getMarkupClass());
+						tag.setMarkupClass(baseMarkup.getMarkupResourceData().getResource()
+								.getMarkupClass());
 						addMarkupElement(tag);
 						break;
 					}
 					else
 					{
 						throw new WicketRuntimeException(
-								"Wicket tags like <wicket:xxx> are not allowed in between <wicket:child> and </wicket:child> tags: "
-										+ markup.toString());
+								"Wicket tags like <wicket:xxx> are not allowed in between <wicket:child> and </wicket:child> tags: " +
+										markup.toString());
 					}
 				}
 				else if (element instanceof ComponentTag)
 				{
 					throw new WicketRuntimeException(
-							"Wicket tags identified by wicket:id are not allowed in between <wicket:child> and </wicket:child> tags: "
-									+ markup.toString());
+							"Wicket tags identified by wicket:id are not allowed in between <wicket:child> and </wicket:child> tags: " +
+									markup.toString());
 				}
 			}
 
@@ -282,10 +293,11 @@
 			// But first add </wicket:child>
 			WicketTag childCloseTag = (WicketTag)childTag.mutable();
 			childCloseTag.getXmlTag().setType(XmlTag.CLOSE);
-			childCloseTag.setMarkupClass(baseMarkup.getMarkupResourceData().getResource().getMarkupClass());
+			childCloseTag.setMarkupClass(baseMarkup.getMarkupResourceData().getResource()
+					.getMarkupClass());
 			addMarkupElement(childCloseTag);
 		}
-		
+
 		for (baseIndex++; baseIndex < baseMarkup.size(); baseIndex++)
 		{
 			MarkupElement element = baseMarkup.get(baseIndex);
@@ -293,10 +305,12 @@
 
 			// Make sure all tags of the base markup remember where they are
 			// from
-			if ((element instanceof ComponentTag) && (baseMarkup.getMarkupResourceData().getResource() != null))
+			if ((element instanceof ComponentTag) &&
+					(baseMarkup.getMarkupResourceData().getResource() != null))
 			{
 				ComponentTag tag = (ComponentTag)element;
-				tag.setMarkupClass(baseMarkup.getMarkupResourceData().getResource().getMarkupClass());
+				tag.setMarkupClass(baseMarkup.getMarkupResourceData().getResource()
+						.getMarkupClass());
 			}
 		}
 
@@ -304,7 +318,8 @@
 		// it must enclose ALL of the <wicket:head> tags.
 		// Note: HtmlHeaderSectionHandler does something similar, but because
 		// markup filters are not called for merged markup again, ...
-		if (Page.class.isAssignableFrom(markup.getMarkupResourceData().getResource().getMarkupClass()))
+		if (Page.class.isAssignableFrom(markup.getMarkupResourceData().getResource()
+				.getMarkupClass()))
 		{
 			// Find the position inside the markup for first <wicket:head>,
 			// last </wicket:head> and <head>
@@ -315,18 +330,18 @@
 			{
 				MarkupElement element = get(i);
 
-				if ((hasOpenWicketHead == -1) && (element instanceof WicketTag)
-						&& ((WicketTag)element).isHeadTag())
+				if ((hasOpenWicketHead == -1) && (element instanceof WicketTag) &&
+						((WicketTag)element).isHeadTag())
 				{
 					hasOpenWicketHead = i;
 				}
-				else if ((element instanceof WicketTag) && ((WicketTag)element).isHeadTag()
-						&& ((WicketTag)element).isClose())
+				else if ((element instanceof WicketTag) && ((WicketTag)element).isHeadTag() &&
+						((WicketTag)element).isClose())
 				{
 					hasCloseWicketHead = i;
 				}
-				else if ((hasHead == -1) && (element instanceof ComponentTag)
-						&& TagUtils.isHeadTag((ComponentTag)element))
+				else if ((hasHead == -1) && (element instanceof ComponentTag) &&
+						TagUtils.isHeadTag((ComponentTag)element))
 				{
 					hasHead = i;
 				}

Added: incubator/wicket/trunk/jdk-1.4/wicket/src/main/java/org/apache/wicket/markup/loader/DefaultMarkupLoader.java
URL: http://svn.apache.org/viewvc/incubator/wicket/trunk/jdk-1.4/wicket/src/main/java/org/apache/wicket/markup/loader/DefaultMarkupLoader.java?view=auto&rev=548018
==============================================================================
--- incubator/wicket/trunk/jdk-1.4/wicket/src/main/java/org/apache/wicket/markup/loader/DefaultMarkupLoader.java (added)
+++ incubator/wicket/trunk/jdk-1.4/wicket/src/main/java/org/apache/wicket/markup/loader/DefaultMarkupLoader.java Sun Jun 17 00:58:20 2007
@@ -0,0 +1,59 @@
+/*
+ * 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.markup.loader;
+
+import java.io.IOException;
+
+import org.apache.wicket.MarkupContainer;
+import org.apache.wicket.markup.Markup;
+import org.apache.wicket.markup.MarkupResourceStream;
+import org.apache.wicket.util.resource.ResourceStreamNotFoundException;
+
+/**
+ * This is Wickets default markup loader. It uses the
+ * InheritedMarkupMarkupLoader and SimpleMarkupLoader to load the markup
+ * associated with a MarkupContainer.
+ * 
+ * @see InheritedMarkupMarkupLoader
+ * @see SimpleMarkupLoader
+ * 
+ * @author Juergen Donnerstag
+ */
+public class DefaultMarkupLoader implements IMarkupLoader
+{
+	/**
+	 * Constructor.
+	 */
+	public DefaultMarkupLoader()
+	{
+	}
+
+	/**
+	 * 
+	 * @see org.apache.wicket.markup.loader.IMarkupLoader#loadMarkup(org.apache.wicket.MarkupContainer,
+	 *      org.apache.wicket.markup.MarkupResourceStream,
+	 *      org.apache.wicket.markup.loader.IMarkupLoader, boolean)
+	 */
+	public final Markup loadMarkup(final MarkupContainer container,
+			final MarkupResourceStream markupResourceStream, final IMarkupLoader baseLoader,
+			final boolean enforceReload) throws IOException, ResourceStreamNotFoundException
+	{
+		IMarkupLoader loader = new InheritedMarkupMarkupLoader();
+		return loader.loadMarkup(container, markupResourceStream, new SimpleMarkupLoader(),
+				enforceReload);
+	}
+}

Propchange: incubator/wicket/trunk/jdk-1.4/wicket/src/main/java/org/apache/wicket/markup/loader/DefaultMarkupLoader.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: incubator/wicket/trunk/jdk-1.4/wicket/src/main/java/org/apache/wicket/markup/loader/IMarkupLoader.java
URL: http://svn.apache.org/viewvc/incubator/wicket/trunk/jdk-1.4/wicket/src/main/java/org/apache/wicket/markup/loader/IMarkupLoader.java?view=auto&rev=548018
==============================================================================
--- incubator/wicket/trunk/jdk-1.4/wicket/src/main/java/org/apache/wicket/markup/loader/IMarkupLoader.java (added)
+++ incubator/wicket/trunk/jdk-1.4/wicket/src/main/java/org/apache/wicket/markup/loader/IMarkupLoader.java Sun Jun 17 00:58:20 2007
@@ -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.markup.loader;
+
+import java.io.IOException;
+
+import org.apache.wicket.MarkupContainer;
+import org.apache.wicket.markup.Markup;
+import org.apache.wicket.markup.MarkupCache;
+import org.apache.wicket.markup.MarkupParser;
+import org.apache.wicket.markup.MarkupParserFactory;
+import org.apache.wicket.markup.MarkupResourceStream;
+import org.apache.wicket.util.resource.ResourceStreamNotFoundException;
+
+/**
+ * IMarkupLoader are loading the actual markup for a specific Wicket container
+ * and resource stream. In case of markup inheritance it means that 2+ markup
+ * files must be read and merged. In order to be flexible the interface has been
+ * designed in a way that multiple IMarkupLoader can be chained to easily build
+ * up more complex loaders.
+ * 
+ * @see MarkupCache
+ * @see MarkupParser
+ * @see MarkupParserFactory
+ * 
+ * @author Juergen Donnerstag
+ */
+public interface IMarkupLoader
+{
+	/**
+	 * Loads markup from a resource stream.
+	 * 
+	 * @param container
+	 *            The original requesting markup container
+	 * @param markupResourceStream
+	 *            The markup resource stream to load
+	 * @param baseLoader
+	 *            This parameter can be use to chain IMarkupLoaders
+	 * @param enforceReload
+	 *            The cache will be ignored and all, including inherited markup
+	 *            files, will be reloaded. Whatever is in the cache, it will be
+	 *            ignored
+	 * @return The markup
+	 * @throws IOException
+	 * @throws ResourceStreamNotFoundException
+	 */
+	Markup loadMarkup(final MarkupContainer container,
+			final MarkupResourceStream markupResourceStream, final IMarkupLoader baseLoader,
+			final boolean enforceReload) throws IOException, ResourceStreamNotFoundException;
+}
\ No newline at end of file

Propchange: incubator/wicket/trunk/jdk-1.4/wicket/src/main/java/org/apache/wicket/markup/loader/IMarkupLoader.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: incubator/wicket/trunk/jdk-1.4/wicket/src/main/java/org/apache/wicket/markup/loader/InheritedMarkupMarkupLoader.java
URL: http://svn.apache.org/viewvc/incubator/wicket/trunk/jdk-1.4/wicket/src/main/java/org/apache/wicket/markup/loader/InheritedMarkupMarkupLoader.java?view=auto&rev=548018
==============================================================================
--- incubator/wicket/trunk/jdk-1.4/wicket/src/main/java/org/apache/wicket/markup/loader/InheritedMarkupMarkupLoader.java (added)
+++ incubator/wicket/trunk/jdk-1.4/wicket/src/main/java/org/apache/wicket/markup/loader/InheritedMarkupMarkupLoader.java Sun Jun 17 00:58:20 2007
@@ -0,0 +1,144 @@
+/*
+ * 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.markup.loader;
+
+import java.io.IOException;
+
+import org.apache.wicket.Application;
+import org.apache.wicket.MarkupContainer;
+import org.apache.wicket.markup.Markup;
+import org.apache.wicket.markup.MarkupElement;
+import org.apache.wicket.markup.MarkupNotFoundException;
+import org.apache.wicket.markup.MarkupResourceStream;
+import org.apache.wicket.markup.MergedMarkup;
+import org.apache.wicket.markup.WicketTag;
+import org.apache.wicket.util.resource.ResourceStreamNotFoundException;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Merge the 2+ markups involved in markup inheritance. From a users perspective
+ * there is only one markup associated with the component, the merged one.
+ * 
+ * @author Juergen Donnerstag
+ */
+public class InheritedMarkupMarkupLoader implements IMarkupLoader
+{
+	/** Log for reporting. */
+	private static final Logger log = LoggerFactory.getLogger(InheritedMarkupMarkupLoader.class);
+
+	/**
+	 * Constructor.
+	 * 
+	 * @param cache
+	 */
+	public InheritedMarkupMarkupLoader()
+	{
+	}
+
+	/**
+	 * 
+	 * @see org.apache.wicket.markup.loader.IMarkupLoader#loadMarkup(org.apache.wicket.MarkupContainer,
+	 *      org.apache.wicket.markup.MarkupResourceStream,
+	 *      org.apache.wicket.markup.loader.IMarkupLoader, boolean)
+	 */
+	public final Markup loadMarkup(final MarkupContainer container,
+			final MarkupResourceStream markupResourceStream, final IMarkupLoader baseLoader,
+			final boolean enforceReload) throws IOException, ResourceStreamNotFoundException
+	{
+		// read and parse the markup
+		Markup markup = baseLoader.loadMarkup(container, markupResourceStream, null, enforceReload);
+		markup = checkForMarkupInheritance(container, markup, enforceReload);
+		return markup;
+	}
+
+	/**
+	 * The markup has just been loaded and now we check if markup inheritance
+	 * applies, which is if <wicket:extend> is found in the markup. If yes, than
+	 * load the base markups and merge the markup elements to create an updated
+	 * (merged) list of markup elements.
+	 * 
+	 * @param container
+	 *            The original requesting markup container
+	 * @param markup
+	 *            The markup to checked for inheritance
+	 * @param enforceReload
+	 *            The cache will be ignored and all, including inherited markup
+	 *            files, will be reloaded. Whatever is in the cache, it will be
+	 *            ignored
+	 * @return A markup object with the the base markup elements resolved.
+	 * @TODO move into IMarkupLoader
+	 */
+	private Markup checkForMarkupInheritance(final MarkupContainer container, final Markup markup,
+			final boolean enforceReload)
+	{
+		// Check if markup contains <wicket:extend> which tells us that
+		// we need to read the inherited markup as well.
+		int extendIndex = requiresBaseMarkup(markup);
+		if (extendIndex == -1)
+		{
+			// return a MarkupStream for the markup
+			return markup;
+		}
+
+		// get the base markup
+		final Markup baseMarkup = Application.get().getMarkupSettings().getMarkupCache().getMarkup(
+				container,
+				markup.getMarkupResourceData().getResource().getMarkupClass().getSuperclass(),
+				enforceReload);
+
+		if (baseMarkup == Markup.NO_MARKUP)
+		{
+			throw new MarkupNotFoundException(
+					"Base markup of inherited markup not found. Component class: " +
+							markup.getMarkupResourceData().getResource().getContainerInfo()
+									.getContainerClass().getName() +
+							" Enable debug messages for org.apache.wicket.util.resource.Resource to get a list of all filenames tried.");
+		}
+
+		// Merge base and derived markup
+		return new MergedMarkup(markup, baseMarkup, extendIndex);
+	}
+
+	/**
+	 * Check if markup contains &lt;wicket:extend&gt; which tells us that we
+	 * need to read the inherited markup as well. &lt;wicket:extend&gt; MUST BE
+	 * the first wicket tag in the markup. Skip raw markup
+	 * 
+	 * @param markup
+	 * @return == 0, if no wicket:extend was found
+	 * @TODO move into IMarkupLoader
+	 */
+	private int requiresBaseMarkup(final Markup markup)
+	{
+		for (int i = 0; i < markup.size(); i++)
+		{
+			MarkupElement elem = (MarkupElement)markup.get(i);
+			if (elem instanceof WicketTag)
+			{
+				WicketTag wtag = (WicketTag)elem;
+				if (wtag.isExtendTag())
+				{
+					// Ok, inheritance is on and we must get the
+					// inherited markup as well.
+					return i;
+				}
+			}
+		}
+		return -1;
+	}
+}

Propchange: incubator/wicket/trunk/jdk-1.4/wicket/src/main/java/org/apache/wicket/markup/loader/InheritedMarkupMarkupLoader.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: incubator/wicket/trunk/jdk-1.4/wicket/src/main/java/org/apache/wicket/markup/loader/SimpleMarkupLoader.java
URL: http://svn.apache.org/viewvc/incubator/wicket/trunk/jdk-1.4/wicket/src/main/java/org/apache/wicket/markup/loader/SimpleMarkupLoader.java?view=auto&rev=548018
==============================================================================
--- incubator/wicket/trunk/jdk-1.4/wicket/src/main/java/org/apache/wicket/markup/loader/SimpleMarkupLoader.java (added)
+++ incubator/wicket/trunk/jdk-1.4/wicket/src/main/java/org/apache/wicket/markup/loader/SimpleMarkupLoader.java Sun Jun 17 00:58:20 2007
@@ -0,0 +1,55 @@
+/*
+ * 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.markup.loader;
+
+import java.io.IOException;
+
+import org.apache.wicket.Application;
+import org.apache.wicket.MarkupContainer;
+import org.apache.wicket.markup.Markup;
+import org.apache.wicket.markup.MarkupResourceStream;
+import org.apache.wicket.util.resource.ResourceStreamNotFoundException;
+
+/**
+ * Load the markup via the MarkupParser, not more, not less. Caching is provided
+ * separately as well as Inherited-Markup merging.
+ * 
+ * @author Juergen Donnerstag
+ */
+public class SimpleMarkupLoader implements IMarkupLoader
+{
+	/**
+	 * Constructor.
+	 */
+	public SimpleMarkupLoader()
+	{
+	}
+
+	/**
+	 * 
+	 * @see org.apache.wicket.markup.loader.IMarkupLoader#loadMarkup(org.apache.wicket.MarkupContainer,
+	 *      org.apache.wicket.markup.MarkupResourceStream,
+	 *      org.apache.wicket.markup.loader.IMarkupLoader, boolean)
+	 */
+	public final Markup loadMarkup(final MarkupContainer container,
+			final MarkupResourceStream markupResourceStream, final IMarkupLoader baseLoader,
+			final boolean enforceReload) throws IOException, ResourceStreamNotFoundException
+	{
+		return Application.get().getMarkupSettings().getMarkupParserFactory().newMarkupParser(
+				markupResourceStream).parse();
+	}
+}

Propchange: incubator/wicket/trunk/jdk-1.4/wicket/src/main/java/org/apache/wicket/markup/loader/SimpleMarkupLoader.java
------------------------------------------------------------------------------
    svn:eol-style = native

Modified: incubator/wicket/trunk/jdk-1.4/wicket/src/main/java/org/apache/wicket/settings/IMarkupSettings.java
URL: http://svn.apache.org/viewvc/incubator/wicket/trunk/jdk-1.4/wicket/src/main/java/org/apache/wicket/settings/IMarkupSettings.java?view=diff&rev=548018&r1=548017&r2=548018
==============================================================================
--- incubator/wicket/trunk/jdk-1.4/wicket/src/main/java/org/apache/wicket/settings/IMarkupSettings.java (original)
+++ incubator/wicket/trunk/jdk-1.4/wicket/src/main/java/org/apache/wicket/settings/IMarkupSettings.java Sun Jun 17 00:58:20 2007
@@ -16,6 +16,7 @@
  */
 package org.apache.wicket.settings;
 
+import org.apache.wicket.markup.IMarkupCache;
 import org.apache.wicket.markup.IMarkupParserFactory;
 import org.apache.wicket.markup.MarkupParserFactory;
 
@@ -72,6 +73,13 @@
 	IMarkupParserFactory getMarkupParserFactory();
 
 	/**
+	 * The markup cache also loads the markup if not yet avaiable in the cache.
+	 * 
+	 * @return markup cache
+	 */
+	IMarkupCache getMarkupCache();
+
+	/**
 	 * @return Returns the stripComments.
 	 * @see IMarkupSettings#setStripComments(boolean)
 	 */
@@ -95,7 +103,8 @@
 	 * Application default for automatic link resolution. Please
 	 * 
 	 * @see org.apache.wicket.markup.resolver.AutoLinkResolver and
-	 * @see org.apache.wicket.markup.parser.filter.WicketLinkTagHandler for more details.
+	 * @see org.apache.wicket.markup.parser.filter.WicketLinkTagHandler for more
+	 *      details.
 	 * 
 	 * @param automaticLinking
 	 *            The automaticLinking to set.
@@ -150,6 +159,15 @@
 	 *            new factory
 	 */
 	void setMarkupParserFactory(IMarkupParserFactory factory);
+
+	/**
+	 * Sets a new markup cache which will also be used to load markup if not yet
+	 * available in the cache.
+	 * 
+	 * @param markupCache
+	 *            new markup cache
+	 */
+	void setMarkupCache(IMarkupCache markupCache);
 
 	/**
 	 * Enables stripping of markup comments denoted in markup by HTML comment

Modified: incubator/wicket/trunk/jdk-1.4/wicket/src/main/java/org/apache/wicket/settings/Settings.java
URL: http://svn.apache.org/viewvc/incubator/wicket/trunk/jdk-1.4/wicket/src/main/java/org/apache/wicket/settings/Settings.java?view=diff&rev=548018&r1=548017&r2=548018
==============================================================================
--- incubator/wicket/trunk/jdk-1.4/wicket/src/main/java/org/apache/wicket/settings/Settings.java (original)
+++ incubator/wicket/trunk/jdk-1.4/wicket/src/main/java/org/apache/wicket/settings/Settings.java Sun Jun 17 00:58:20 2007
@@ -34,7 +34,9 @@
 import org.apache.wicket.authorization.IAuthorizationStrategy;
 import org.apache.wicket.authorization.IUnauthorizedComponentInstantiationListener;
 import org.apache.wicket.authorization.UnauthorizedInstantiationException;
+import org.apache.wicket.markup.IMarkupCache;
 import org.apache.wicket.markup.IMarkupParserFactory;
+import org.apache.wicket.markup.MarkupCache;
 import org.apache.wicket.markup.MarkupParserFactory;
 import org.apache.wicket.markup.html.IPackageResourceGuard;
 import org.apache.wicket.markup.html.PackageResourceGuard;
@@ -169,6 +171,9 @@
 	/** Factory for creating markup parsers */
 	private IMarkupParserFactory markupParserFactory;
 
+	/** A markup cache which will load the markup if required. */
+	private IMarkupCache markupCache;
+	
 	/** To help prevent denial of service attacks */
 	private int maxPageMaps = 5;
 
@@ -1239,5 +1244,27 @@
 	public boolean isOutputMarkupContainerClassName()
 	{
 		return outputMarkupContainerClassName;
+	}
+
+	/**
+	 * @see org.apache.wicket.settings.IMarkupSettings#getMarkupCache()
+	 */
+	public IMarkupCache getMarkupCache()
+	{
+		if (this.markupCache == null)
+		{
+			// Construct markup cache for this application
+			this.markupCache = new MarkupCache();
+		}
+
+		return this.markupCache;
+	}
+
+	/**
+	 * @see org.apache.wicket.settings.IMarkupSettings#setMarkupCache(org.apache.wicket.markup.MarkupCache)
+	 */
+	public void setMarkupCache(final IMarkupCache markupCache)
+	{
+		this.markupCache = markupCache;
 	}
 }

Modified: incubator/wicket/trunk/jdk-1.4/wicket/src/main/java/org/apache/wicket/util/watch/ModificationWatcher.java
URL: http://svn.apache.org/viewvc/incubator/wicket/trunk/jdk-1.4/wicket/src/main/java/org/apache/wicket/util/watch/ModificationWatcher.java?view=diff&rev=548018&r1=548017&r2=548018
==============================================================================
--- incubator/wicket/trunk/jdk-1.4/wicket/src/main/java/org/apache/wicket/util/watch/ModificationWatcher.java (original)
+++ incubator/wicket/trunk/jdk-1.4/wicket/src/main/java/org/apache/wicket/util/watch/ModificationWatcher.java Sun Jun 17 00:58:20 2007
@@ -20,6 +20,7 @@
 import java.util.HashMap;
 import java.util.Iterator;
 import java.util.Map;
+import java.util.Set;
 
 import org.apache.wicket.util.listener.ChangeListenerSet;
 import org.apache.wicket.util.listener.IChangeListener;
@@ -190,5 +191,13 @@
 		{
 			task.stop();
 		}
+	}
+	
+	/**
+	 * @return Gets all IModifiable entries currently maintained
+	 */
+	public final Set getEntries()
+	{
+		return this.modifiableToEntry.keySet();
 	}
 }