Author: jdonnerstag Date: Sun Jun 5 09:56:36 2011 New Revision: 1132358 URL: http://svn.apache.org/viewvc?rev=1132358&view=rev Log: some minor changes. Mostly javadoc and inline docs for clarification. Issue: WICKET-3741
Modified: wicket/trunk/wicket-core/src/main/java/org/apache/wicket/Session.java wicket/trunk/wicket-core/src/main/java/org/apache/wicket/markup/ContainerInfo.java wicket/trunk/wicket-core/src/main/java/org/apache/wicket/markup/DefaultMarkupResourceStreamProvider.java wicket/trunk/wicket-core/src/main/java/org/apache/wicket/markup/MarkupCache.java wicket/trunk/wicket-core/src/main/java/org/apache/wicket/markup/MarkupFactory.java wicket/trunk/wicket-core/src/main/java/org/apache/wicket/markup/MarkupStream.java wicket/trunk/wicket-core/src/main/java/org/apache/wicket/markup/MarkupType.java wicket/trunk/wicket-core/src/main/java/org/apache/wicket/markup/html/border/MarkupComponentBorder.java wicket/trunk/wicket-core/src/main/java/org/apache/wicket/markup/html/form/FormComponent.java wicket/trunk/wicket-core/src/main/java/org/apache/wicket/markup/loader/InheritedMarkupMarkupLoader.java wicket/trunk/wicket-core/src/main/java/org/apache/wicket/markup/parser/IXmlPullParser.java wicket/trunk/wicket-core/src/main/java/org/apache/wicket/markup/parser/XmlPullParser.java wicket/trunk/wicket-core/src/main/java/org/apache/wicket/page/PageAccessSynchronizer.java wicket/trunk/wicket-core/src/main/java/org/apache/wicket/pageStore/AsynchronousDataStore.java wicket/trunk/wicket-core/src/main/java/org/apache/wicket/util/string/interpolator/PropertyVariableInterpolator.java wicket/trunk/wicket-core/src/test/java/org/apache/wicket/markup/MarkupCacheTest.java wicket/trunk/wicket-core/src/test/java/org/apache/wicket/markup/MarkupParserTest.java Modified: wicket/trunk/wicket-core/src/main/java/org/apache/wicket/Session.java URL: http://svn.apache.org/viewvc/wicket/trunk/wicket-core/src/main/java/org/apache/wicket/Session.java?rev=1132358&r1=1132357&r2=1132358&view=diff ============================================================================== --- wicket/trunk/wicket-core/src/main/java/org/apache/wicket/Session.java (original) +++ wicket/trunk/wicket-core/src/main/java/org/apache/wicket/Session.java Sun Jun 5 09:56:36 2011 @@ -856,6 +856,8 @@ public abstract class Session implements private static final class PageAccessSynchronizerProvider extends LazyInitializer<PageAccessSynchronizer> { + private static final long serialVersionUID = 1L; + @Override protected PageAccessSynchronizer createInstance() { Modified: wicket/trunk/wicket-core/src/main/java/org/apache/wicket/markup/ContainerInfo.java URL: http://svn.apache.org/viewvc/wicket/trunk/wicket-core/src/main/java/org/apache/wicket/markup/ContainerInfo.java?rev=1132358&r1=1132357&r2=1132358&view=diff ============================================================================== --- wicket/trunk/wicket-core/src/main/java/org/apache/wicket/markup/ContainerInfo.java (original) +++ wicket/trunk/wicket-core/src/main/java/org/apache/wicket/markup/ContainerInfo.java Sun Jun 5 09:56:36 2011 @@ -34,7 +34,7 @@ public class ContainerInfo private final Locale locale; private final String style; private final String variation; - private final String fileExtension; + private final MarkupType markupType; /** * Construct. @@ -45,7 +45,7 @@ public class ContainerInfo public ContainerInfo(final MarkupContainer container) { this(container.getClass(), container.getLocale(), container.getStyle(), - container.getVariation(), container.getMarkupType().getExtension()); + container.getVariation(), container.getMarkupType()); } /** @@ -55,24 +55,24 @@ public class ContainerInfo * @param locale * @param style * @param variation - * @param fileExtension + * @param markupType */ public ContainerInfo(final Class<?> containerClass, final Locale locale, final String style, - final String variation, final String fileExtension) + final String variation, final MarkupType markupType) { super(); containerClassRef = new WeakReference<Class<?>>(containerClass); this.locale = locale; this.style = style; this.variation = variation; - this.fileExtension = fileExtension; + this.markupType = markupType; } /** * * @return The container class */ - public Class getContainerClass() + public Class<?> getContainerClass() { return containerClassRef.get(); } @@ -83,7 +83,7 @@ public class ContainerInfo */ public String getFileExtension() { - return fileExtension; + return markupType != null ? markupType.getExtension() : null; } /** @@ -122,6 +122,6 @@ public class ContainerInfo { Class<?> classRef = containerClassRef.get(); return (classRef != null ? classRef.getName() : "null class") + ":" + locale + ":" + style + - ":" + fileExtension; + ":" + markupType; } } Modified: wicket/trunk/wicket-core/src/main/java/org/apache/wicket/markup/DefaultMarkupResourceStreamProvider.java URL: http://svn.apache.org/viewvc/wicket/trunk/wicket-core/src/main/java/org/apache/wicket/markup/DefaultMarkupResourceStreamProvider.java?rev=1132358&r1=1132357&r2=1132358&view=diff ============================================================================== --- wicket/trunk/wicket-core/src/main/java/org/apache/wicket/markup/DefaultMarkupResourceStreamProvider.java (original) +++ wicket/trunk/wicket-core/src/main/java/org/apache/wicket/markup/DefaultMarkupResourceStreamProvider.java Sun Jun 5 09:56:36 2011 @@ -33,8 +33,7 @@ import org.slf4j.LoggerFactory; * @author Jonathan Locke * @author Juergen Donnerstag */ -public class - DefaultMarkupResourceStreamProvider implements IMarkupResourceStreamProvider +public class DefaultMarkupResourceStreamProvider implements IMarkupResourceStreamProvider { /** Log for reporting. */ @@ -74,7 +73,9 @@ public class String style = container.getStyle(); String variation = container.getVariation(); Locale locale = container.getLocale(); - String ext = container.getMarkupType().getExtension(); + + MarkupType markupType = container.getMarkupType(); + String ext = (markupType != null ? markupType.getExtension() : null); // Markup is associated with the containers class. Walk up the class // hierarchy up to MarkupContainer to find the containers markup Modified: wicket/trunk/wicket-core/src/main/java/org/apache/wicket/markup/MarkupCache.java URL: http://svn.apache.org/viewvc/wicket/trunk/wicket-core/src/main/java/org/apache/wicket/markup/MarkupCache.java?rev=1132358&r1=1132357&r2=1132358&view=diff ============================================================================== --- wicket/trunk/wicket-core/src/main/java/org/apache/wicket/markup/MarkupCache.java (original) +++ wicket/trunk/wicket-core/src/main/java/org/apache/wicket/markup/MarkupCache.java Sun Jun 5 09:56:36 2011 @@ -39,8 +39,8 @@ import org.slf4j.LoggerFactory; * 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. + * MarkupCache is registered with {@link MarkupFactory} which in turn is registered with + * {@link IMarkupSettings} and thus can be replaced with a subclassed version. * * @see IMarkupSettings * @see MarkupFactory @@ -54,16 +54,21 @@ public class MarkupCache implements IMar private static final Logger log = LoggerFactory.getLogger(MarkupCache.class); /** The actual cache: location => Markup */ - private final ICache<CharSequence, Markup> markupCache; + private final ICache<String, Markup> markupCache; - /** Add extra indirection to the cache: key => location */ - private final ICache<CharSequence, CharSequence> markupKeyCache; + /** + * Add extra indirection to the cache: key => location + * <p> + * Since ConcurrentHashMap does not allow to store null values, we are using Markup.NO_MARKUP + * instead. + */ + private final ICache<String, String> markupKeyCache; /** The markup cache key provider used by MarkupCache */ private IMarkupCacheKeyProvider markupCacheKeyProvider; /** - * Note that you can not use Application.get() since removeMarkup() will be call from a + * Note that you can not use Application.get() since removeMarkup() will be called from a * ModificationWatcher thread which has no associated Application. */ private final Application application; @@ -89,25 +94,20 @@ public class MarkupCache implements IMar application = Application.get(); markupCache = newCacheImplementation(); - markupKeyCache = newCacheImplementation(); if (markupCache == null) { throw new WicketRuntimeException("The map used to cache markup must not be null"); } + + markupKeyCache = newCacheImplementation(); } - /** - * {@inheritDoc} - */ public void clear() { markupCache.clear(); markupKeyCache.clear(); } - /** - * {@inheritDoc} - */ public void shutdown() { markupCache.shutdown(); @@ -115,7 +115,8 @@ public class MarkupCache implements IMar } /** - * {@inheritDoc} + * Note that this method will be called from a "cleanup" thread which might not have a thread + * local application. */ public final IMarkupFragment removeMarkup(final String cacheKey) { @@ -127,26 +128,29 @@ public class MarkupCache implements IMar } // Remove the markup from the cache - CharSequence locationString = markupKeyCache.get(cacheKey); - IMarkupFragment markup = markupCache.get(locationString); + String locationString = markupKeyCache.get(cacheKey); + IMarkupFragment markup = (locationString != null ? markupCache.get(locationString) : null); if (markup != null) { + // Found an entry: actual markup or Markup.NO_MARKUP. Null values are not possible + // because of ConcurrentHashMap. markupCache.remove(locationString); // If a base markup file has been removed from the cache, than // the derived markup should be removed as well. - // Repeat until all depend resources have been removed (count == 0) - int count; - do + // Repeat until all dependent resources have been removed (count == 0) + int count = 1; + while (count > 0) { + // Reset prior to next round count = 0; // Iterate though all entries of the cache - Iterator<CharSequence> iter = markupCache.getKeys().iterator(); + Iterator<String> iter = markupCache.getKeys().iterator(); while (iter.hasNext()) { - CharSequence key = iter.next(); + String key = iter.next(); // Check if the markup associated with key has a base markup. And if yes, test // if that is cached. @@ -162,14 +166,14 @@ public class MarkupCache implements IMar } } } - 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 called from a // ModificationWatcher thread which has no associated Application. + IModificationWatcher watcher = application.getResourceSettings().getResourceWatcher( - true); + false); if (watcher != null) { Iterator<IModifiable> iter = watcher.getEntries().iterator(); @@ -186,6 +190,7 @@ public class MarkupCache implements IMar } } } + return markup; } @@ -193,15 +198,22 @@ public class MarkupCache implements IMar * @param key * @return True, if base markup for entry with cache 'key' is available in the cache as well. */ - private boolean isBaseMarkupCached(final CharSequence key) + private boolean isBaseMarkupCached(final String key) { - // Get the markup associated with key + // Get the markup associated with key. Null in case the key has no associated value. A null + // value is not possible because of ConcurrentHashMap. Markup markup = markupCache.get(key); if (markup == null) { return false; } + // NO_MARKUP does not have an associated resource stream + if (markup == Markup.NO_MARKUP) + { + return false; + } + // Get the base markup resource stream from the markup MarkupResourceStream resourceStream = markup.getMarkupResourceStream() .getBaseMarkupResourceStream(); @@ -219,18 +231,18 @@ public class MarkupCache implements IMar if (resourceStream != null) { String key = resourceStream.getCacheKey(); - CharSequence locationString = markupKeyCache.get(key); - if ((locationString != null) && (markupCache.get(locationString) == null)) + if (key != null) { - return true; + String locationString = markupKeyCache.get(key); + if ((locationString != null) && (markupCache.get(locationString) != null)) + { + return true; + } } } return false; } - /** - * {@inheritDoc} - */ public final int size() { return markupCache.size(); @@ -239,43 +251,34 @@ public class MarkupCache implements IMar /** * Get a unmodifiable map which contains the cached data. The map key is of type String and the * value is of type Markup. + * <p> + * May be used to debug or iterate the cache content. * * @return cache implementation */ - protected final ICache<CharSequence, Markup> getMarkupCache() + public final ICache<String, Markup> getMarkupCache() { return markupCache; } - /** - * THIS IS NOT PART OF WICKET'S PUBLIC API. DO NOT USE IT. - * - * 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, - * Class, boolean) - */ public final Markup getMarkup(final MarkupContainer container, final Class<?> clazz, final boolean enforceReload) { - Class<?> containerClass = clazz; - if (clazz == null) - { - containerClass = container.getClass(); - } - else if (!clazz.isAssignableFrom(container.getClass())) - { - throw new WicketRuntimeException("Parameter clazz must be an instance of " + - container.getClass().getName() + ", but is a " + clazz.getName()); - } + Class<?> containerClass = MarkupFactory.get().getContainerClass(container, clazz); - // Get the cache key to be associated with the markup resource stream + // Get the cache key to be associated with the markup resource stream. + // If the cacheKey returned == null, than caching is disabled for the resource stream. final String cacheKey = getMarkupCacheKeyProvider(container).getCacheKey(container, containerClass); // Is the markup already in the cache? - Markup markup = (enforceReload == false ? getMarkupFromCache(cacheKey, container) : null); + Markup markup = null; + if ((enforceReload == false) && (cacheKey != null)) + { + markup = getMarkupFromCache(cacheKey, container); + } + + // If markup not found in cache or cache disabled, than ... if (markup == null) { if (log.isDebugEnabled()) @@ -283,8 +286,7 @@ public class MarkupCache implements IMar 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 + // Get the markup resource stream for the container final MarkupResourceStream resourceStream = MarkupFactory.get() .getMarkupResourceStream(container, containerClass); @@ -298,33 +300,49 @@ public class MarkupCache implements IMar } else { - markup = onMarkupNotFound(cacheKey, container); + markup = onMarkupNotFound(cacheKey, container, Markup.NO_MARKUP); } } + + // NO_MARKUP should only be used insight the Cache. + if (markup == Markup.NO_MARKUP) + { + markup = null; + } + return markup; } /** - * Will be called if the markup was not in the cache yet but could not be found either. + * Will be called if the markup was not in the cache yet and 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 + * Subclasses may change the default implementation. E.g. they might choose not to update the + * cache to enforce reloading of any markup not found. This might be useful in very dynamic * environments. * * @param cacheKey * @param container - * @return Markup.NO_MARKUP + * @param markup + * Markup.NO_MARKUP + * @return Same as parameter "markup" */ - protected Markup onMarkupNotFound(final String cacheKey, final MarkupContainer container) + protected Markup onMarkupNotFound(final String cacheKey, final MarkupContainer container, + final Markup markup) { if (log.isDebugEnabled()) { log.debug("Markup not found: " + cacheKey); } - // flag markup as non-existent - markupKeyCache.put(cacheKey, cacheKey); - return putIntoCache(cacheKey, container, Markup.NO_MARKUP); + // If cacheKey == null, than caching is disabled for the component + if (cacheKey != null) + { + // flag markup as non-existent + markupKeyCache.put(cacheKey, cacheKey); + putIntoCache(cacheKey, container, markup); + } + + return markup; } /** @@ -342,13 +360,20 @@ public class MarkupCache implements IMar * @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 locationString, MarkupContainer container, + protected Markup putIntoCache(final String locationString, final MarkupContainer container, Markup markup) { if (locationString != null) { if (markupCache.containsKey(locationString) == false) { + // The default cache implementation is a ConcurrentHashMap. Thus neither the key nor + // the value can be null. + if (markup == null) + { + markup = Markup.NO_MARKUP; + } + markupCache.put(locationString, markup); } else @@ -376,11 +401,11 @@ public class MarkupCache implements IMar * @param container * @return null, if not found or to enforce reloading the markup */ - protected Markup getMarkupFromCache(final CharSequence cacheKey, final MarkupContainer container) + protected Markup getMarkupFromCache(final String cacheKey, final MarkupContainer container) { if (cacheKey != null) { - CharSequence locationString = markupKeyCache.get(cacheKey); + String locationString = markupKeyCache.get(cacheKey); if (locationString != null) { return markupCache.get(locationString); @@ -399,7 +424,7 @@ public class MarkupCache implements IMar * @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 + * @return The markup. Markup.NO_MARKUP, if not found. */ private final Markup loadMarkup(final MarkupContainer container, final MarkupResourceStream markupResourceStream, final boolean enforceReload) @@ -432,7 +457,7 @@ public class MarkupCache implements IMar return markup; } - // In case of an error, remove the cache entry + // In case the markup could not be loaded (without exception), than .. if (cacheKey != null) { removeMarkup(cacheKey); @@ -458,6 +483,8 @@ public class MarkupCache implements IMar private final Markup loadMarkupAndWatchForChanges(final MarkupContainer container, final MarkupResourceStream markupResourceStream, final boolean enforceReload) { + // @TODO the following code sequence looks very much like in loadMarkup. Can it be + // optimized? final String cacheKey = markupResourceStream.getCacheKey(); if (cacheKey != null) { @@ -477,8 +504,7 @@ public class MarkupCache implements IMar } // Watch file in the future - final IModificationWatcher watcher = Application.get() - .getResourceSettings() + final IModificationWatcher watcher = application.getResourceSettings() .getResourceWatcher(true); if (watcher != null) { @@ -599,9 +625,9 @@ public class MarkupCache implements IMar * Put an entry into the cache * * @param key - * The reference key to find the element + * The reference key to find the element. Must not be null. * @param value - * The element to be cached + * The element to be cached. Must not be null. */ void put(K key, V value); @@ -617,6 +643,7 @@ public class MarkupCache implements IMar */ public static class DefaultCacheImplementation<K, V> implements ICache<K, V> { + // Neither key nor value are allowed to be null with ConcurrentHashMap private final ConcurrentHashMap<K, V> cache = new ConcurrentHashMap<K, V>(); /** @@ -626,18 +653,12 @@ public class MarkupCache implements IMar { } - /** - * {@inheritDoc} - */ public void clear() { cache.clear(); } - /** - * {@inheritDoc} - */ - public boolean containsKey(Object key) + public boolean containsKey(final Object key) { if (key == null) { @@ -646,10 +667,7 @@ public class MarkupCache implements IMar return cache.containsKey(key); } - /** - * {@inheritDoc} - */ - public V get(Object key) + public V get(final Object key) { if (key == null) { @@ -658,41 +676,31 @@ public class MarkupCache implements IMar return cache.get(key); } - /** - * {@inheritDoc} - */ public Collection<K> getKeys() { return cache.keySet(); } - /** - * {@inheritDoc} - */ public void put(K key, V value) { + // Note that neither key nor value are allowed to be null with ConcurrentHashMap cache.put(key, value); } - /** - * {@inheritDoc} - */ public boolean remove(K key) { + if (key == null) + { + return false; + } return cache.remove(key) == null; } - /** - * {@inheritDoc} - */ public int size() { return cache.size(); } - /** - * {@inheritDoc} - */ public void shutdown() { clear(); Modified: wicket/trunk/wicket-core/src/main/java/org/apache/wicket/markup/MarkupFactory.java URL: http://svn.apache.org/viewvc/wicket/trunk/wicket-core/src/main/java/org/apache/wicket/markup/MarkupFactory.java?rev=1132358&r1=1132357&r2=1132358&view=diff ============================================================================== --- wicket/trunk/wicket-core/src/main/java/org/apache/wicket/markup/MarkupFactory.java (original) +++ wicket/trunk/wicket-core/src/main/java/org/apache/wicket/markup/MarkupFactory.java Sun Jun 5 09:56:36 2011 @@ -35,6 +35,11 @@ import org.slf4j.LoggerFactory; /** * Factory to load markup either from from cache or from a resource. In case of markup inheritance, * merging the markup is managed transparently. + * <p> + * This class is the main entry point to load markup. Nothing else should be required by Components. + * It managed caching markup as well as loading and merging (inheritance) of markup. + * <p> + * The markup returned is immutable as it gets re-used across multiple Component instances. * * @author Juergen Donnerstag */ @@ -106,9 +111,6 @@ public class MarkupFactory // Markup parsers can not be re-used return new MarkupParser(newXmlPullParser(), resource) { - /** - * @see org.apache.wicket.markup.MarkupParser#onAppendMarkupFilter(org.apache.wicket.markup.parser.IMarkupFilter) - */ @Override protected IMarkupFilter onAppendMarkupFilter(final IMarkupFilter filter) { @@ -178,14 +180,16 @@ public class MarkupFactory } /** - * Get the markup associated with the container. + * Get the markup associated with the container. This is mostly likely what you need to get the + * markup for a component. * * @param container * The container to find the markup for * @param enforceReload * If true, 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 associated with the container + * @return The markup associated with the container. Null, if the markup was not found or could + * not yet be loaded (e.g. getMarkupType() == null). Wicket Exception in case of errors. */ public final Markup getMarkup(final MarkupContainer container, final boolean enforceReload) { @@ -193,32 +197,75 @@ public class MarkupFactory } /** - * Get the markup associated with the container. + * Get the markup associated with the container. Check the cache first. If not found, than load + * the markup and update the cache. + * <p> + * The clazz parameter usually can be null, except for base (inherited) markup. + * <p> + * There several means to disable markup caching. Caching can be disabled alltogether - + * getMarkupCache() return null -, or individually (cacheKey == null). * * @param container * The container to find the markup for * @param clazz - * Must be the container class or any of its super classes. + * Must be the container class or any of its super classes. May be null. * @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 associated with the container + * @return The markup associated with the container. Null, if the markup was not found or could + * not yet be loaded (e.g. getMarkupType() == null). Wicket Exception in case of errors. */ public final Markup getMarkup(final MarkupContainer container, final Class<?> clazz, final boolean enforceReload) { Args.notNull(container, "container"); - Args.notNull(clazz, "clazz"); + + if (checkMarkupType(container) == false) + { + return null; + } + + Class<?> containerClass = getContainerClass(container, clazz); IMarkupCache cache = getMarkupCache(); if (cache != null) { // MarkupCache acts as pull-through cache. It'll call the same loadMarkup() method as // below, if needed. - return cache.getMarkup(container, clazz, enforceReload); + // @TODO may that can be changed. I don't like it too much. + return cache.getMarkup(container, containerClass, enforceReload); + } + + // Get the markup resource stream for the container (and super class) + MarkupResourceStream markupResourceStream = getMarkupResourceStream(container, + containerClass); + + return loadMarkup(container, markupResourceStream, enforceReload); + } + + /** + * Without a markup type we can not search for a file and we can not construct the cacheKey. We + * can not even load associated markup as required for Panels. Though every MarkupContainer can + * provide it's own type, by default they refer to the Page. Hence, no markup type is an + * indicator, that the component or any of its parents, has not yet been added. + * + * @param container + * @return true, if container.getMarkupType() != null + */ + protected final boolean checkMarkupType(final MarkupContainer container) + { + if (container.getMarkupType() == null) + { + if (log.isDebugEnabled()) + { + log.debug("Markup file not loaded, since the markup type is not yet available: " + + container.toString()); + } + + return false; } - return loadMarkup(container, null, enforceReload); + return true; } /** @@ -227,10 +274,13 @@ public class MarkupFactory * @param container * The container to find the markup for * @return True if this markup container has associated markup + * @deprecated please use {@link #getMarkup(MarkupContainer, boolean)} instead */ + @Deprecated public final boolean hasAssociatedMarkup(final MarkupContainer container) { - return getMarkup(container, false) != Markup.NO_MARKUP; + Markup markup = getMarkup(container, false); + return markup != null && markup != Markup.NO_MARKUP; } /** @@ -260,28 +310,28 @@ public class MarkupFactory } /** - * Create a new markup resource stream for the container. + * Create a new markup resource stream for the container and optionally the Class. The Class + * must be provided in case of base (inherited) markup. Else it might be null (standard use + * case). * * @param container * The MarkupContainer which requests to load the Markup resource stream * @param clazz - * Either the container class or any super class + * Either the container class or any super class. Might be null. * @return A IResourceStream if the resource was found */ public final MarkupResourceStream getMarkupResourceStream(final MarkupContainer container, Class<?> clazz) { - Class<?> containerClass = clazz; - if (clazz == null) - { - containerClass = container.getClass(); - } - else if (!clazz.isAssignableFrom(container.getClass())) + Args.notNull(container, "container"); + + if (checkMarkupType(container) == false) { - throw new WicketRuntimeException("Parameter clazz must be an instance of " + - container.getClass().getName() + ", but is a " + clazz.getName()); + return null; } + Class<?> containerClass = getContainerClass(container, clazz); + // 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( @@ -292,47 +342,128 @@ public class MarkupFactory { return null; } + if (resourceStream instanceof MarkupResourceStream) { return (MarkupResourceStream)resourceStream; } + return new MarkupResourceStream(resourceStream, new ContainerInfo(container), containerClass); } /** - * Loads markup from a resource stream. + * Gets and checks the container class + * + * @param container + * @param clazz + * Either null, or a super class of container + * @return The container class to be used + */ + public final Class<?> getContainerClass(final MarkupContainer container, final Class<?> clazz) + { + Args.notNull(container, "container"); + + Class<?> containerClass = clazz; + if (clazz == null) + { + containerClass = container.getClass(); + } + else if (!clazz.isAssignableFrom(container.getClass())) + { + throw new IllegalArgumentException("Parameter clazz must be an instance of " + + container.getClass().getName() + ", but is a " + clazz.getName()); + } + return containerClass; + } + + /** + * Loads markup from a resource stream. It'll call the registered markup loader to load the + * markup. + * <p> + * Though the 'enforceReload' attribute seem to imply that the cache is consulted to retrieve + * the markup, the cache in fact is only checked for retrieving the base (inherited) markup. + * Please see {@link #getMarkup(MarkupContainer, boolean)} as well. * * @param container * The original requesting markup container * @param markupResourceStream - * The markup resource stream to load. May be null. + * The markup resource stream to load, if already known. * @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 + * @return The markup. Null, if the markup was not found. Wicket Exception in case of errors. */ public final Markup loadMarkup(final MarkupContainer container, - MarkupResourceStream markupResourceStream, final boolean enforceReload) + final MarkupResourceStream markupResourceStream, final boolean enforceReload) { - if (markupResourceStream == null) + // @TODO can markupResourceStream be replace with clazz??? + Args.notNull(container, "container"); + Args.notNull(markupResourceStream, "markupResourceStream"); + + if (checkMarkupType(container) == false) { - markupResourceStream = getMarkupResourceStream(container, null); + return null; } try { + // The InheritedMarkupMarkupLoader needs to load the base markup. It'll do it via + // MarkupFactory.getMarkup() as main entry point, which in tern allows to choose between + // use or ignore the cache. That's via we need to propagate enforceReload to the markup + // loader as well. + + // Markup loader is responsible to load the full markup for the container. In case of + // markup inheritance, the markup must be merged from different markup files. It is the + // merged markup which eventually will be cached, thus avoiding repetitive merge + // operations, which always result in the same outcome. + // The base markup will still be cached though, in order to avoid any unnecessary + // reloads. The base markup itself might be merged as it might inherit from its base + // class. + return getMarkupLoader().loadMarkup(container, markupResourceStream, null, enforceReload); } + catch (MarkupNotFoundException e) + { + // InheritedMarkupMarkupLoader will throw a MarkupNotFoundException in case the + // <b>base</b> markup can not be found. + + log.error("Markup not found: " + e.getMessage(), e); + + // Catch exception and ignore => return null (markup not found) + } catch (ResourceStreamNotFoundException e) { - log.error("Unable to find markup from " + markupResourceStream, e); + log.error("Markup not found: " + markupResourceStream, e); + + // Catch exception and ignore => return null (markup not found) } catch (IOException e) { - log.error("Unable to read markup from " + markupResourceStream, e); + log.error("Error while reading the markup " + markupResourceStream, e); + + // Wrap with wicket exception and re-throw + throw new MarkupException(markupResourceStream, "IO error while readin markup: " + + e.getMessage(), e); + } + catch (WicketRuntimeException e) + { + log.error("Error while reading the markup " + markupResourceStream, e); + + // re-throw + throw e; } + catch (RuntimeException e) + { + log.error("Error while reading the markup " + markupResourceStream, e); + + // Wrap with wicket exception and re-throw + throw new MarkupException(markupResourceStream, "Error while reading the markup: " + + e.getMessage(), e); + } + + // Markup not found. Errors should throw a Wicket exception return null; } } Modified: wicket/trunk/wicket-core/src/main/java/org/apache/wicket/markup/MarkupStream.java URL: http://svn.apache.org/viewvc/wicket/trunk/wicket-core/src/main/java/org/apache/wicket/markup/MarkupStream.java?rev=1132358&r1=1132357&r2=1132358&view=diff ============================================================================== --- wicket/trunk/wicket-core/src/main/java/org/apache/wicket/markup/MarkupStream.java (original) +++ wicket/trunk/wicket-core/src/main/java/org/apache/wicket/markup/MarkupStream.java Sun Jun 5 09:56:36 2011 @@ -17,6 +17,7 @@ package org.apache.wicket.markup; import org.apache.wicket.Component; +import org.apache.wicket.util.lang.Args; import org.apache.wicket.util.resource.IResourceStream; import org.apache.wicket.util.string.Strings; @@ -61,10 +62,7 @@ public class MarkupStream */ public MarkupStream(final IMarkupFragment markup) { - if (markup == null) - { - throwMarkupException("Failed to find markup."); - } + Args.notNull(markup, "markup"); this.markup = markup; Modified: wicket/trunk/wicket-core/src/main/java/org/apache/wicket/markup/MarkupType.java URL: http://svn.apache.org/viewvc/wicket/trunk/wicket-core/src/main/java/org/apache/wicket/markup/MarkupType.java?rev=1132358&r1=1132357&r2=1132358&view=diff ============================================================================== --- wicket/trunk/wicket-core/src/main/java/org/apache/wicket/markup/MarkupType.java (original) +++ wicket/trunk/wicket-core/src/main/java/org/apache/wicket/markup/MarkupType.java Sun Jun 5 09:56:36 2011 @@ -65,4 +65,10 @@ public class MarkupType implements Seria { return mimeType; } + + @Override + public String toString() + { + return "MarkupType [extension=" + extension + ", mimeType=" + mimeType + "]"; + } } Modified: wicket/trunk/wicket-core/src/main/java/org/apache/wicket/markup/html/border/MarkupComponentBorder.java URL: http://svn.apache.org/viewvc/wicket/trunk/wicket-core/src/main/java/org/apache/wicket/markup/html/border/MarkupComponentBorder.java?rev=1132358&r1=1132357&r2=1132358&view=diff ============================================================================== --- wicket/trunk/wicket-core/src/main/java/org/apache/wicket/markup/html/border/MarkupComponentBorder.java (original) +++ wicket/trunk/wicket-core/src/main/java/org/apache/wicket/markup/html/border/MarkupComponentBorder.java Sun Jun 5 09:56:36 2011 @@ -30,6 +30,7 @@ import org.apache.wicket.markup.MarkupEl import org.apache.wicket.markup.MarkupFactory; import org.apache.wicket.markup.MarkupResourceStream; import org.apache.wicket.markup.MarkupStream; +import org.apache.wicket.markup.MarkupType; import org.apache.wicket.markup.WicketTag; import org.apache.wicket.markup.parser.filter.WicketTagIdentifier; import org.apache.wicket.request.Response; @@ -168,7 +169,11 @@ public class MarkupComponentBorder exten */ private MarkupStream findMarkupStream(final Component owner) { - final String markupType = getMarkupType(owner); + final MarkupType markupType = getMarkupType(owner); + if (markupType == null) + { + return null; + } // TODO we need to expose this functionality for any class not just for // markupcontainers in markupcache so we don't have to replicate this @@ -190,7 +195,7 @@ public class MarkupComponentBorder exten { String path = containerClass.getName().replace('.', '/'); IResourceStream resourceStream = locator.locate(containerClass, path, style, variation, - locale, markupType, false); + locale, markupType.getExtension(), false); // Did we find it already? if (resourceStream != null) @@ -245,17 +250,17 @@ public class MarkupComponentBorder exten * @param component * @return markup type */ - private String getMarkupType(final Component component) + private MarkupType getMarkupType(final Component component) { - String extension; + final MarkupType markupType; if (component instanceof MarkupContainer) { - extension = ((MarkupContainer)component).getMarkupType().getExtension(); + markupType = ((MarkupContainer)component).getMarkupType(); } else { - extension = component.getParent().getMarkupType().getExtension(); + markupType = component.getParent().getMarkupType(); } - return extension; + return markupType; } } Modified: wicket/trunk/wicket-core/src/main/java/org/apache/wicket/markup/html/form/FormComponent.java URL: http://svn.apache.org/viewvc/wicket/trunk/wicket-core/src/main/java/org/apache/wicket/markup/html/form/FormComponent.java?rev=1132358&r1=1132357&r2=1132358&view=diff ============================================================================== --- wicket/trunk/wicket-core/src/main/java/org/apache/wicket/markup/html/form/FormComponent.java (original) +++ wicket/trunk/wicket-core/src/main/java/org/apache/wicket/markup/html/form/FormComponent.java Sun Jun 5 09:56:36 2011 @@ -442,7 +442,7 @@ public abstract class FormComponent<T> e * if the value is not set the default value equivalent to component id will be returned. * * @param fc - * @return + * @return Localized label string */ public final String getDefaultLabel() { Modified: wicket/trunk/wicket-core/src/main/java/org/apache/wicket/markup/loader/InheritedMarkupMarkupLoader.java URL: http://svn.apache.org/viewvc/wicket/trunk/wicket-core/src/main/java/org/apache/wicket/markup/loader/InheritedMarkupMarkupLoader.java?rev=1132358&r1=1132357&r2=1132358&view=diff ============================================================================== --- wicket/trunk/wicket-core/src/main/java/org/apache/wicket/markup/loader/InheritedMarkupMarkupLoader.java (original) +++ wicket/trunk/wicket-core/src/main/java/org/apache/wicket/markup/loader/InheritedMarkupMarkupLoader.java Sun Jun 5 09:56:36 2011 @@ -59,13 +59,12 @@ public class InheritedMarkupMarkupLoader int extendIndex = requiresBaseMarkup(markup); if (extendIndex == -1) { - // return a MarkupStream for the markup return markup; } // Load the base markup final Markup baseMarkup = getBaseMarkup(container, markup, enforceReload); - if (baseMarkup == Markup.NO_MARKUP) + if ((baseMarkup == null) || (baseMarkup == Markup.NO_MARKUP)) { throw new MarkupNotFoundException( "Base markup of inherited markup not found. Component class: " + Modified: wicket/trunk/wicket-core/src/main/java/org/apache/wicket/markup/parser/IXmlPullParser.java URL: http://svn.apache.org/viewvc/wicket/trunk/wicket-core/src/main/java/org/apache/wicket/markup/parser/IXmlPullParser.java?rev=1132358&r1=1132357&r2=1132358&view=diff ============================================================================== --- wicket/trunk/wicket-core/src/main/java/org/apache/wicket/markup/parser/IXmlPullParser.java (original) +++ wicket/trunk/wicket-core/src/main/java/org/apache/wicket/markup/parser/IXmlPullParser.java Sun Jun 5 09:56:36 2011 @@ -146,11 +146,8 @@ public interface IXmlPullParser * Use null to apply JVM/OS default * @throws IOException * Error while reading the resource - * @throws ResourceStreamNotFoundException - * Resource not found */ - void parse(InputStream inputStream, final String encoding) throws IOException, - ResourceStreamNotFoundException; + void parse(InputStream inputStream, final String encoding) throws IOException; /** * Move to the next XML element Modified: wicket/trunk/wicket-core/src/main/java/org/apache/wicket/markup/parser/XmlPullParser.java URL: http://svn.apache.org/viewvc/wicket/trunk/wicket-core/src/main/java/org/apache/wicket/markup/parser/XmlPullParser.java?rev=1132358&r1=1132357&r2=1132358&view=diff ============================================================================== --- wicket/trunk/wicket-core/src/main/java/org/apache/wicket/markup/parser/XmlPullParser.java (original) +++ wicket/trunk/wicket-core/src/main/java/org/apache/wicket/markup/parser/XmlPullParser.java Sun Jun 5 09:56:36 2011 @@ -27,6 +27,7 @@ import org.apache.wicket.markup.parser.X import org.apache.wicket.util.io.FullyBufferedReader; import org.apache.wicket.util.io.IOUtils; import org.apache.wicket.util.io.XmlReader; +import org.apache.wicket.util.lang.Args; import org.apache.wicket.util.parse.metapattern.parsers.TagNameParser; import org.apache.wicket.util.parse.metapattern.parsers.VariableAssignmentParser; import org.apache.wicket.util.resource.ResourceStreamNotFoundException; @@ -558,11 +559,11 @@ public final class XmlPullParser impleme * @param encoding * The default character encoding of the input * @throws IOException - * @throws ResourceStreamNotFoundException */ - public void parse(final InputStream inputStream, final String encoding) throws IOException, - ResourceStreamNotFoundException + public void parse(final InputStream inputStream, final String encoding) throws IOException { + Args.notNull(inputStream, "inputStream"); + try { xmlReader = new XmlReader(new BufferedInputStream(inputStream, 4000), encoding); @@ -570,14 +571,8 @@ public final class XmlPullParser impleme } finally { - try - { - inputStream.close(); - } - finally - { - IOUtils.close(xmlReader); - } + IOUtils.closeQuietly(inputStream); + IOUtils.closeQuietly(xmlReader); } } Modified: wicket/trunk/wicket-core/src/main/java/org/apache/wicket/page/PageAccessSynchronizer.java URL: http://svn.apache.org/viewvc/wicket/trunk/wicket-core/src/main/java/org/apache/wicket/page/PageAccessSynchronizer.java?rev=1132358&r1=1132357&r2=1132358&view=diff ============================================================================== --- wicket/trunk/wicket-core/src/main/java/org/apache/wicket/page/PageAccessSynchronizer.java (original) +++ wicket/trunk/wicket-core/src/main/java/org/apache/wicket/page/PageAccessSynchronizer.java Sun Jun 5 09:56:36 2011 @@ -35,11 +35,15 @@ import org.slf4j.LoggerFactory; */ public class PageAccessSynchronizer implements Serializable { + private static final long serialVersionUID = 1L; + private static final Logger logger = LoggerFactory.getLogger(PageAccessSynchronizer.class); /** map of which pages are owned by which threads */ private IProvider<ConcurrentMap<Integer, PageLock>> locks = new LazyInitializer<ConcurrentMap<Integer, PageLock>>() { + private static final long serialVersionUID = 1L; + @Override protected ConcurrentMap<Integer, PageLock> createInstance() { Modified: wicket/trunk/wicket-core/src/main/java/org/apache/wicket/pageStore/AsynchronousDataStore.java URL: http://svn.apache.org/viewvc/wicket/trunk/wicket-core/src/main/java/org/apache/wicket/pageStore/AsynchronousDataStore.java?rev=1132358&r1=1132357&r2=1132358&view=diff ============================================================================== --- wicket/trunk/wicket-core/src/main/java/org/apache/wicket/pageStore/AsynchronousDataStore.java (original) +++ wicket/trunk/wicket-core/src/main/java/org/apache/wicket/pageStore/AsynchronousDataStore.java Sun Jun 5 09:56:36 2011 @@ -23,6 +23,9 @@ import java.util.concurrent.ConcurrentHa import java.util.concurrent.ConcurrentLinkedQueue; import java.util.concurrent.atomic.AtomicBoolean; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + /** * Facade for {@link IDataStore} that does the actual saving in worker thread. * @@ -30,6 +33,9 @@ import java.util.concurrent.atomic.Atomi */ public class AsynchronousDataStore implements IDataStore { + /** Log for reporting. */ + private static final Logger log = LoggerFactory.getLogger(AsynchronousDataStore.class); + private static final Object WRITE_LOCK = new Object(); private final AtomicBoolean destroy = new AtomicBoolean(false); @@ -74,7 +80,7 @@ public class AsynchronousDataStore imple } catch (InterruptedException e) { - e.printStackTrace(); + log.error(e.getMessage(), e); } dataStore.destroy(); @@ -257,7 +263,7 @@ public class AsynchronousDataStore imple } catch (InterruptedException e) { - e.printStackTrace(); + log.error(e.getMessage(), e); } } @@ -279,7 +285,7 @@ public class AsynchronousDataStore imple } catch (InterruptedException e) { - e.printStackTrace(); + log.error(e.getMessage(), e); } synchronized (destroy) Modified: wicket/trunk/wicket-core/src/main/java/org/apache/wicket/util/string/interpolator/PropertyVariableInterpolator.java URL: http://svn.apache.org/viewvc/wicket/trunk/wicket-core/src/main/java/org/apache/wicket/util/string/interpolator/PropertyVariableInterpolator.java?rev=1132358&r1=1132357&r2=1132358&view=diff ============================================================================== --- wicket/trunk/wicket-core/src/main/java/org/apache/wicket/util/string/interpolator/PropertyVariableInterpolator.java (original) +++ wicket/trunk/wicket-core/src/main/java/org/apache/wicket/util/string/interpolator/PropertyVariableInterpolator.java Sun Jun 5 09:56:36 2011 @@ -43,6 +43,8 @@ public final class PropertyVariableInter implements IConverterLocator { + private static final long serialVersionUID = 1L; + /** The model to introspect on */ private final Object model; Modified: wicket/trunk/wicket-core/src/test/java/org/apache/wicket/markup/MarkupCacheTest.java URL: http://svn.apache.org/viewvc/wicket/trunk/wicket-core/src/test/java/org/apache/wicket/markup/MarkupCacheTest.java?rev=1132358&r1=1132357&r2=1132358&view=diff ============================================================================== --- wicket/trunk/wicket-core/src/test/java/org/apache/wicket/markup/MarkupCacheTest.java (original) +++ wicket/trunk/wicket-core/src/test/java/org/apache/wicket/markup/MarkupCacheTest.java Sun Jun 5 09:56:36 2011 @@ -45,10 +45,10 @@ public class MarkupCacheTest extends Wic public void testMarkupNotFoundInformationIsCachedInDeploymentMode() { IMarkupFragment markup = cache.getMarkup(component, null, false); - assertEquals(Markup.NO_MARKUP, markup); + assertNull(markup); markup = cache.getMarkup(component, null, false); - assertEquals(Markup.NO_MARKUP, markup); + assertNull(markup); } private static class MarkupCachingAssumingComponent extends Panel Modified: wicket/trunk/wicket-core/src/test/java/org/apache/wicket/markup/MarkupParserTest.java URL: http://svn.apache.org/viewvc/wicket/trunk/wicket-core/src/test/java/org/apache/wicket/markup/MarkupParserTest.java?rev=1132358&r1=1132357&r2=1132358&view=diff ============================================================================== --- wicket/trunk/wicket-core/src/test/java/org/apache/wicket/markup/MarkupParserTest.java (original) +++ wicket/trunk/wicket-core/src/test/java/org/apache/wicket/markup/MarkupParserTest.java Sun Jun 5 09:56:36 2011 @@ -635,7 +635,6 @@ public final class MarkupParserTest exte */ public void testIEConditionalComments() throws Exception { - boolean stripComments = tester.getApplication().getMarkupSettings().getStripComments(); try {