Source Code Cross Referenced for MarkupCache.java in  » J2EE » wicket » wicket » markup » Java Source Code / Java DocumentationJava Source Code and Java Documentation

Java Source Code / Java Documentation
1. 6.0 JDK Core
2. 6.0 JDK Modules
3. 6.0 JDK Modules com.sun
4. 6.0 JDK Modules com.sun.java
5. 6.0 JDK Modules sun
6. 6.0 JDK Platform
7. Ajax
8. Apache Harmony Java SE
9. Aspect oriented
10. Authentication Authorization
11. Blogger System
12. Build
13. Byte Code
14. Cache
15. Chart
16. Chat
17. Code Analyzer
18. Collaboration
19. Content Management System
20. Database Client
21. Database DBMS
22. Database JDBC Connection Pool
23. Database ORM
24. Development
25. EJB Server geronimo
26. EJB Server GlassFish
27. EJB Server JBoss 4.2.1
28. EJB Server resin 3.1.5
29. ERP CRM Financial
30. ESB
31. Forum
32. GIS
33. Graphic Library
34. Groupware
35. HTML Parser
36. IDE
37. IDE Eclipse
38. IDE Netbeans
39. Installer
40. Internationalization Localization
41. Inversion of Control
42. Issue Tracking
43. J2EE
44. JBoss
45. JMS
46. JMX
47. Library
48. Mail Clients
49. Net
50. Parser
51. PDF
52. Portal
53. Profiler
54. Project Management
55. Report
56. RSS RDF
57. Rule Engine
58. Science
59. Scripting
60. Search Engine
61. Security
62. Sevlet Container
63. Source Control
64. Swing Library
65. Template Engine
66. Test Coverage
67. Testing
68. UML
69. Web Crawler
70. Web Framework
71. Web Mail
72. Web Server
73. Web Services
74. Web Services apache cxf 2.0.1
75. Web Services AXIS2
76. Wiki Engine
77. Workflow Engines
78. XML
79. XML UI
Java
Java Tutorial
Java Open Source
Jar File Download
Java Articles
Java Products
Java by API
Photoshop Tutorials
Maya Tutorials
Flash Tutorials
3ds-Max Tutorials
Illustrator Tutorials
GIMP Tutorials
C# / C Sharp
C# / CSharp Tutorial
C# / CSharp Open Source
ASP.Net
ASP.NET Tutorial
JavaScript DHTML
JavaScript Tutorial
JavaScript Reference
HTML / CSS
HTML CSS Reference
C / ANSI-C
C Tutorial
C++
C++ Tutorial
Ruby
PHP
Python
Python Tutorial
Python Open Source
SQL Server / T-SQL
SQL Server / T-SQL Tutorial
Oracle PL / SQL
Oracle PL/SQL Tutorial
PostgreSQL
SQL / MySQL
MySQL Tutorial
VB.Net
VB.Net Tutorial
Flash / Flex / ActionScript
VBA / Excel / Access / Word
XML
XML Tutorial
Microsoft Office PowerPoint 2007 Tutorial
Microsoft Office Excel 2007 Tutorial
Microsoft Office Word 2007 Tutorial
Java Source Code / Java Documentation » J2EE » wicket » wicket.markup 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


001:        /*
002:         * $Id: MarkupCache.java 4639 2006-02-26 01:44:07 -0800 (Sun, 26 Feb 2006)
003:         * jdonnerstag $ $Revision: 463947 $ $Date: 2006-02-26 01:44:07 -0800 (Sun, 26 Feb
004:         * 2006) $
005:         * 
006:         * ==============================================================================
007:         * Licensed under the Apache License, Version 2.0 (the "License"); you may not
008:         * use this file except in compliance with the License. You may obtain a copy of
009:         * the License at
010:         * 
011:         * http://www.apache.org/licenses/LICENSE-2.0
012:         * 
013:         * Unless required by applicable law or agreed to in writing, software
014:         * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
015:         * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
016:         * License for the specific language governing permissions and limitations under
017:         * the License.
018:         */
019:        package wicket.markup;
020:
021:        import java.io.IOException;
022:        import java.util.Iterator;
023:        import java.util.Locale;
024:        import java.util.Map;
025:
026:        import org.apache.commons.logging.Log;
027:        import org.apache.commons.logging.LogFactory;
028:
029:        import wicket.Application;
030:        import wicket.MarkupContainer;
031:        import wicket.WicketRuntimeException;
032:        import wicket.util.concurrent.ConcurrentHashMap;
033:        import wicket.util.listener.IChangeListener;
034:        import wicket.util.resource.IResourceStream;
035:        import wicket.util.resource.ResourceStreamNotFoundException;
036:        import wicket.util.string.AppendingStringBuffer;
037:        import wicket.util.watch.ModificationWatcher;
038:        import wicket.util.watch.Watcher;
039:
040:        /**
041:         * Load markup and cache it for fast retrieval. If markup file changes, it'll be
042:         * removed and subsequently reloaded when needed.
043:         * 
044:         * @author Jonathan Locke
045:         * @author Juergen Donnerstag
046:         */
047:        public class MarkupCache {
048:            /** Log for reporting. */
049:            private static final Log log = LogFactory.getLog(MarkupCache.class);
050:
051:            /** Map of markup tags by class (exactly what is in the file). */
052:            private final Map markupCache = new ConcurrentHashMap();
053:
054:            /**
055:             * Markup inheritance requires that merged markup gets re-merged either
056:             * AFTER the base markup or the derived markup has been reloaded.
057:             */
058:            private final Watcher afterLoadListeners = new Watcher();
059:
060:            /** The Wicket application */
061:            private final Application application;
062:
063:            /**
064:             * Constructor.
065:             * 
066:             * @param application
067:             */
068:            public MarkupCache(final Application application) {
069:                this .application = application;
070:            }
071:
072:            /**
073:             * Gets a fresh markup stream that contains the (immutable) markup resource
074:             * for this class.
075:             * 
076:             * @param container
077:             *            The container the markup should be associated with
078:             * @return A stream of MarkupElement elements
079:             */
080:            public final MarkupStream getMarkupStream(
081:                    final MarkupContainer container) {
082:                return getMarkupStream(container, true);
083:            }
084:
085:            /**
086:             * Gets a fresh markup stream that contains the (immutable) markup resource
087:             * for this class.
088:             * 
089:             * @param container
090:             *            The container the markup should be associated with
091:             * @param throwException
092:             *            If true, throw an exception, if markup could not be found
093:             * @return A stream of MarkupElement elements
094:             */
095:            public final MarkupStream getMarkupStream(
096:                    final MarkupContainer container,
097:                    final boolean throwException) {
098:                if (container == null) {
099:                    throw new IllegalArgumentException(
100:                            "Parameter 'container' must not be 'null'.");
101:                }
102:
103:                // Look for associated markup
104:                final Markup markup = getMarkup(container, container.getClass());
105:
106:                // If we found markup for this container
107:                if (markup != Markup.NO_MARKUP) {
108:                    return new MarkupStream(markup);
109:                }
110:
111:                if (throwException == true) {
112:                    // throw exception since there is no associated markup
113:                    throw new MarkupNotFoundException(
114:                            "Markup not found. Component class: "
115:                                    + container.getClass().getName()
116:                                    + " Enable debug messages for wicket.util.resource to get a list of all filenames tried");
117:                }
118:
119:                return null;
120:            }
121:
122:            /**
123:             * Check if container has associated markup
124:             * 
125:             * @param container
126:             *            The container the markup should be associated with
127:             * @return True if this markup container has associated markup
128:             */
129:            public final boolean hasAssociatedMarkup(
130:                    final MarkupContainer container) {
131:                return getMarkup(container, container.getClass()) != Markup.NO_MARKUP;
132:            }
133:
134:            /**
135:             * Gets any (immutable) markup resource for the container or any of its
136:             * parent classes (markup inheritance)
137:             * 
138:             * @param container
139:             *            The original requesting markup container
140:             * @param clazz
141:             *            The class to get the associated markup for. If null, the
142:             *            container's class is used, but it can be a parent class of the
143:             *            container as well (markup inheritance)
144:             * @return Markup resource
145:             */
146:            private final Markup getMarkup(final MarkupContainer container,
147:                    final Class clazz) {
148:                Class containerClass = clazz;
149:                if (clazz == null) {
150:                    containerClass = container.getClass();
151:                } else {
152:                    if (!clazz.isAssignableFrom(container.getClass())) {
153:                        throw new WicketRuntimeException(
154:                                "Parameter clazz must be instance of container");
155:                    }
156:                }
157:
158:                // Look up markup tag list by class, locale, style and markup type
159:                final CharSequence key = markupKey(container, clazz);
160:                Markup markup = (Markup) markupCache.get(key);
161:
162:                // If no markup in the cache
163:                if (markup == null) {
164:                    synchronized (markupCache) {
165:                        markup = (Markup) markupCache.get(key);
166:
167:                        // If no markup is in the cache
168:                        if (markup == null) {
169:                            // Ask the container to locate its associated markup
170:                            final IResourceStream resourceStream = container
171:                                    .newMarkupResourceStream(containerClass);
172:
173:                            // Found markup?
174:                            if (resourceStream != null) {
175:                                final MarkupResourceStream markupResource;
176:                                if (resourceStream instanceof  MarkupResourceStream) {
177:                                    markupResource = (MarkupResourceStream) resourceStream;
178:                                } else {
179:                                    markupResource = new MarkupResourceStream(
180:                                            resourceStream, new ContainerInfo(
181:                                                    container), containerClass);
182:                                }
183:
184:                                // load the markup and watch for changes
185:                                markup = loadMarkupAndWatchForChanges(
186:                                        container, key, markupResource);
187:                            } else {
188:                                // flag markup as non-existent (as opposed to null,
189:                                // which might mean that it's simply not loaded into
190:                                // the cache)
191:                                markup = Markup.NO_MARKUP;
192:
193:                                // Save any markup list (or absence of one) for next
194:                                // time
195:                                markupCache.put(key, markup);
196:                            }
197:                        }
198:                    }
199:                }
200:                return markup;
201:            }
202:
203:            /**
204:             * Remove the markup from the cache and trigger all associated listeners
205:             * 
206:             * @param key
207:             *            The cache key
208:             * @param markupResourceStream
209:             *            The resource stream
210:             */
211:            private void removeMarkup(final CharSequence key,
212:                    final MarkupResourceStream markupResourceStream) {
213:                markupCache.remove(key);
214:
215:                // trigger all listeners registered on the markup that is removed
216:                afterLoadListeners.notifyListeners(markupResourceStream);
217:                afterLoadListeners.remove(markupResourceStream);
218:            }
219:
220:            /**
221:             * Remove the markup from the cache and trigger all associated listeners
222:             * 
223:             * @since 1.2.3
224:             * @param markupResourceStream
225:             *            The resource stream
226:             */
227:            public void removeMarkup(
228:                    final MarkupResourceStream markupResourceStream) {
229:                CharSequence key = null;
230:                Iterator iter = this .markupCache.entrySet().iterator();
231:                while (iter.hasNext()) {
232:                    Map.Entry entry = (Map.Entry) iter.next();
233:                    if (entry.getValue() == markupResourceStream) {
234:                        key = (CharSequence) entry.getKey();
235:                        break;
236:                    }
237:                }
238:
239:                if (key != null) {
240:                    removeMarkup(key, markupResourceStream);
241:                }
242:            }
243:
244:            /**
245:             * Loads markup from a resource stream.
246:             * 
247:             * @param container
248:             *            The original requesting markup container
249:             * @param key
250:             *            Key under which markup should be cached
251:             * @param markupResourceStream
252:             *            The markup resource stream to load
253:             * @return The markup
254:             */
255:            private final Markup loadMarkup(final MarkupContainer container,
256:                    final CharSequence key,
257:                    final MarkupResourceStream markupResourceStream) {
258:                try {
259:                    // read and parse the markup
260:                    Markup markup = application.getMarkupSettings()
261:                            .getMarkupParserFactory().newMarkupParser()
262:                            .readAndParse(markupResourceStream);
263:
264:                    // Check for markup inheritance. If it contains <wicket:extend>
265:                    // the two markups get merged.
266:                    markup = checkForMarkupInheritance(container, key, markup);
267:
268:                    // add the markup to the cache
269:                    markupCache.put(key, markup);
270:
271:                    // trigger all listeners registered on the markup just loaded
272:                    afterLoadListeners.notifyListeners(markupResourceStream);
273:
274:                    return markup;
275:                } catch (ResourceStreamNotFoundException e) {
276:                    log.error("Unable to find markup from "
277:                            + markupResourceStream, e);
278:                } catch (IOException e) {
279:                    log.error("Unable to read markup from "
280:                            + markupResourceStream, e);
281:                }
282:
283:                synchronized (markupCache) {
284:                    markupCache.remove(key);
285:                    afterLoadListeners.remove(markupResourceStream);
286:                }
287:
288:                return Markup.NO_MARKUP;
289:            }
290:
291:            /**
292:             * Load markup from an IResourceStream and add an {@link IChangeListener}to
293:             * the {@link ModificationWatcher} so that if the resource changes, we can
294:             * remove it from the cache automatically and subsequently reload when
295:             * needed.
296:             * 
297:             * @param container
298:             *            The original requesting markup container
299:             * @param key
300:             *            The key for the resource
301:             * @param markupResourceStream
302:             *            The markup stream to load and begin to watch
303:             * @return The markup in the stream
304:             */
305:            private final Markup loadMarkupAndWatchForChanges(
306:                    final MarkupContainer container, final CharSequence key,
307:                    final MarkupResourceStream markupResourceStream) {
308:                // Watch file in the future
309:                final ModificationWatcher watcher = application
310:                        .getResourceSettings().getResourceWatcher();
311:                if (watcher != null) {
312:                    watcher.add(markupResourceStream, new IChangeListener() {
313:                        public void onChange() {
314:                            if (log.isDebugEnabled()) {
315:                                log.debug("Remove markup from cache: "
316:                                        + markupResourceStream);
317:                            }
318:
319:                            // Remove the markup from the cache. It will be reloaded
320:                            // next time it the markup is requested.
321:                            removeMarkup(key, markupResourceStream);
322:                            watcher.remove(markupResourceStream);
323:                        }
324:                    });
325:                }
326:
327:                if (log.isDebugEnabled()) {
328:                    log.debug("Loading markup from " + markupResourceStream);
329:                }
330:                return loadMarkup(container, key, markupResourceStream);
331:            }
332:
333:            /**
334:             * Construct a proper key value for the cache
335:             * 
336:             * @param container
337:             *            The container requesting the markup
338:             * @param clazz
339:             *            The clazz to get the key for
340:             * @return Key that uniquely identifies any markup that might be associated
341:             *         with this markup container.
342:             */
343:            private final CharSequence markupKey(
344:                    final MarkupContainer container, final Class clazz) {
345:                final String classname = clazz.getName();
346:                final Locale locale = container.getLocale();
347:                final String style = container.getStyle();
348:                final String markupType = container.getMarkupType();
349:
350:                final AppendingStringBuffer buffer = new AppendingStringBuffer(
351:                        classname.length() + 32);
352:                buffer.append(classname);
353:
354:                if (locale != null) {
355:                    boolean l = locale.getLanguage().length() != 0;
356:                    boolean c = locale.getCountry().length() != 0;
357:                    boolean v = locale.getVariant().length() != 0;
358:                    buffer.append(locale.getLanguage());
359:                    if (c || (l && v)) {
360:                        buffer.append('_').append(locale.getCountry()); // This may just
361:                        // append '_'
362:                    }
363:                    if (v && (l || c)) {
364:                        buffer.append('_').append(locale.getVariant());
365:                    }
366:                }
367:                if (style != null) {
368:                    buffer.append(style);
369:                }
370:
371:                buffer.append(markupType);
372:                return buffer;
373:            }
374:
375:            /**
376:             * Clear markup cache and force reload of all markup data
377:             */
378:            public void clear() {
379:                this .afterLoadListeners.clear();
380:                this .markupCache.clear();
381:            }
382:
383:            /**
384:             * @return the number of elements currently in the cache.
385:             */
386:            public int size() {
387:                return markupCache.size();
388:            }
389:
390:            /**
391:             * The markup has just been loaded and now we check if markup inheritance
392:             * applies, which is if <wicket:extend> is found in the markup. If yes, than
393:             * load the base markups and merge the markup elements to create an updated
394:             * (merged) list of markup elements.
395:             * 
396:             * @param container
397:             *            The original requesting markup container
398:             * @param key
399:             *            Key under which markup should be cached
400:             * @param markup
401:             *            The markup to checked for inheritance
402:             * @return A markup object with the the base markup elements resolved.
403:             */
404:            private Markup checkForMarkupInheritance(
405:                    final MarkupContainer container, final CharSequence key,
406:                    final Markup markup) {
407:                // Check if markup contains <wicket:extend> which tells us that
408:                // we need to read the inherited markup as well.
409:                int extendIndex = requiresBaseMarkup(markup);
410:                if (extendIndex == -1) {
411:                    // return a MarkupStream for the markup
412:                    return markup;
413:                }
414:
415:                // get the base markup
416:                final Markup baseMarkup = getMarkup(container, markup
417:                        .getResource().getMarkupClass().getSuperclass());
418:
419:                if (baseMarkup == Markup.NO_MARKUP) {
420:                    throw new MarkupNotFoundException(
421:                            "Parent markup of inherited markup not found. Component class: "
422:                                    + markup.getResource().getContainerInfo()
423:                                            .getContainerClass().getName()
424:                                    + " Enable debug messages for wicket.util.resource.Resource to get a list of all filenames tried.");
425:                }
426:
427:                // register an after-load listener for base markup. The listener
428:                // implementation will remove the derived markup which must be merged
429:                // with the base markup
430:                afterLoadListeners.add(baseMarkup.getResource(),
431:                        new IChangeListener() {
432:                            public void onChange() {
433:                                if (log.isDebugEnabled()) {
434:                                    log
435:                                            .debug("Remove derived markup from cache: "
436:                                                    + markup.getResource());
437:                                }
438:                                removeMarkup(key, markup.getResource());
439:                            }
440:
441:                            /**
442:                             * Make sure there is only one listener per derived markup
443:                             * 
444:                             * @see java.lang.Object#equals(java.lang.Object)
445:                             */
446:                            public boolean equals(Object obj) {
447:                                return true;
448:                            }
449:
450:                            /**
451:                             * Make sure there is only one listener per derived markup
452:                             * 
453:                             * @see java.lang.Object#hashCode()
454:                             */
455:                            public int hashCode() {
456:                                return key.hashCode();
457:                            }
458:                        });
459:
460:                // Merge base and derived markup
461:                Markup mergedMarkup = new MergedMarkup(markup, baseMarkup,
462:                        extendIndex);
463:                return mergedMarkup;
464:            }
465:
466:            /**
467:             * Check if markup contains &lt;wicket:extend&gt; which tells us that we
468:             * need to read the inherited markup as well. &lt;wicket:extend&gt; MUST BE
469:             * the first wicket tag in the markup. Skip raw markup
470:             * 
471:             * @param markup
472:             * @return == 0, if no wicket:extend was found
473:             */
474:            private int requiresBaseMarkup(final Markup markup) {
475:                for (int i = 0; i < markup.size(); i++) {
476:                    MarkupElement elem = (MarkupElement) markup.get(i);
477:                    if (elem instanceof  WicketTag) {
478:                        WicketTag wtag = (WicketTag) elem;
479:                        if (wtag.isExtendTag()) {
480:                            // Ok, inheritance is on and we must get the
481:                            // inherited markup as well.
482:                            return i;
483:                        }
484:                    }
485:                }
486:                return -1;
487:            }
488:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.