Source Code Cross Referenced for MarkupContainer.java in  » J2EE » wicket » wicket » 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 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


0001:        /*
0002:         * $Id: MarkupContainer.java 4965 2006-03-16 11:21:07 -0800 (Thu, 16 Mar 2006)
0003:         * ivaynberg $ $Revision: 461664 $ $Date: 2006-03-16 11:21:07 -0800 (Thu, 16 Mar
0004:         * 2006) $
0005:         * 
0006:         * ==============================================================================
0007:         * Licensed under the Apache License, Version 2.0 (the "License"); you may not
0008:         * use this file except in compliance with the License. You may obtain a copy of
0009:         * the License at
0010:         * 
0011:         * http://www.apache.org/licenses/LICENSE-2.0
0012:         * 
0013:         * Unless required by applicable law or agreed to in writing, software
0014:         * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
0015:         * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
0016:         * License for the specific language governing permissions and limitations under
0017:         * the License.
0018:         */
0019:        package wicket;
0020:
0021:        import java.util.ArrayList;
0022:        import java.util.Arrays;
0023:        import java.util.Collections;
0024:        import java.util.Comparator;
0025:        import java.util.Iterator;
0026:        import java.util.List;
0027:
0028:        import org.apache.commons.logging.Log;
0029:        import org.apache.commons.logging.LogFactory;
0030:
0031:        import wicket.feedback.IFeedback;
0032:        import wicket.markup.ComponentTag;
0033:        import wicket.markup.ContainerInfo;
0034:        import wicket.markup.MarkupElement;
0035:        import wicket.markup.MarkupException;
0036:        import wicket.markup.MarkupNotFoundException;
0037:        import wicket.markup.MarkupResourceStream;
0038:        import wicket.markup.MarkupStream;
0039:        import wicket.markup.WicketTag;
0040:        import wicket.markup.resolver.IComponentResolver;
0041:        import wicket.model.ICompoundModel;
0042:        import wicket.model.IModel;
0043:        import wicket.util.resource.IResourceStream;
0044:        import wicket.util.resource.locator.IResourceStreamLocator;
0045:        import wicket.util.string.Strings;
0046:        import wicket.version.undo.Change;
0047:
0048:        /**
0049:         * A MarkupContainer holds a map of child components.
0050:         * <ul>
0051:         * <li><b>Children </b>- Children can be added by calling the add() method, and
0052:         * they can be looked up using a dotted path. For example, if a container called
0053:         * "a" held a nested container "b" which held a nested component "c", then
0054:         * a.get("b.c") would return the Component with id "c". The number of children
0055:         * in a MarkupContainer can be determined by calling size(), and the whole
0056:         * hierarchy of children held by a MarkupContainer can be traversed by calling
0057:         * visitChildren(), passing in an implementation of Component.IVisitor.
0058:         * 
0059:         * <li><b>Markup Rendering </b>- A MarkupContainer also holds/references
0060:         * associated markup which is used to render the container. As the markup stream
0061:         * for a container is rendered, component references in the markup are resolved
0062:         * by using the container to look up Components in the container's component map
0063:         * by id. Each component referenced by the markup stream is given an opportunity
0064:         * to render itself using the markup stream.
0065:         * <p>
0066:         * Components may alter their referring tag, replace the tag's body or insert
0067:         * markup after the tag. But components cannot remove tags from the markup
0068:         * stream. This is an important guarantee because graphic designers may be
0069:         * setting attributes on component tags that affect visual presentation.
0070:         * <p>
0071:         * The type of markup held in a given container subclass can be determined by
0072:         * calling getMarkupType(). Markup is accessed via a MarkupStream object which
0073:         * allows a component to traverse ComponentTag and RawMarkup MarkupElements
0074:         * while rendering a response. Markup in the stream may be HTML or some other
0075:         * kind of markup, such as VXML, as determined by the specific container
0076:         * subclass.
0077:         * <p>
0078:         * A markup stream may be directly associated with a container via
0079:         * setMarkupStream. However, a container which does not have a markup stream
0080:         * (its getMarkupStream() returns null) may inherit a markup stream from a
0081:         * container above it in the component hierarchy. The findMarkupStream() method
0082:         * will locate the first container at or above this container which has a markup
0083:         * stream.
0084:         * <p>
0085:         * All Page containers set a markup stream before rendering by calling the
0086:         * method getAssociatedMarkupStream() to load the markup associated with the
0087:         * page. Since Page is at the top of the container hierarchy, it is guaranteed
0088:         * that findMarkupStream will always return a valid markup stream.
0089:         * 
0090:         * @see MarkupStream
0091:         * @author Jonathan Locke
0092:         */
0093:        public abstract class MarkupContainer extends Component {
0094:            private static final long serialVersionUID = 1L;
0095:
0096:            /** Log for reporting. */
0097:            private static final Log log = LogFactory
0098:                    .getLog(MarkupContainer.class);
0099:
0100:            /** List of children or single child */
0101:            private Object children;
0102:
0103:            /**
0104:             * The markup stream for this container. This variable is used only during
0105:             * the render phase to provide access to the current element within the
0106:             * stream.
0107:             */
0108:            private transient MarkupStream markupStream;
0109:
0110:            /**
0111:             * @see wicket.Component#Component(String)
0112:             */
0113:            public MarkupContainer(final String id) {
0114:                super (id);
0115:            }
0116:
0117:            /**
0118:             * @see wicket.Component#Component(String, IModel)
0119:             */
0120:            public MarkupContainer(final String id, IModel model) {
0121:                super (id, model);
0122:            }
0123:
0124:            /**
0125:             * Adds a child component to this container.
0126:             * <p>
0127:             * Be careful when overriding this method, if not implemented properly it
0128:             * may lead to a java component hierarchy which no longer matches the
0129:             * template hierarchy, which in turn will lead to an error.
0130:             * 
0131:             * @param child
0132:             *            The child
0133:             * @throws IllegalArgumentException
0134:             *             Thrown if a child with the same id is replaced by the add
0135:             *             operation.
0136:             * @return This
0137:             */
0138:            public final MarkupContainer add(final Component child) {
0139:                if (child == null) {
0140:                    throw new IllegalArgumentException(
0141:                            "argument child may not be null");
0142:                }
0143:
0144:                if (log.isDebugEnabled()) {
0145:                    log.debug("Add " + child.getId() + " to " + this );
0146:                }
0147:
0148:                // Add to map
0149:                addedComponent(child);
0150:                if (put(child) != null) {
0151:                    throw new IllegalArgumentException(
0152:                            exceptionMessage("A child with id '"
0153:                                    + child.getId() + "' already exists"));
0154:                }
0155:
0156:                return this ;
0157:            }
0158:
0159:            /**
0160:             * This method allows a component to be added by an auto-resolver such as
0161:             * AutoComponentResolver or AutoLinkResolver. While the component is being
0162:             * added, the component's FLAG_AUTO boolean is set. The isAuto() method of
0163:             * Component returns true if a component or any of its parents has this bit
0164:             * set. When a component is added via autoAdd(), the logic in Page that
0165:             * normally (a) checks for modifications during the rendering process, and
0166:             * (b) versions components, is bypassed if Component.isAuto() returns true.
0167:             * <p>
0168:             * The result of all this is that components added with autoAdd() are free
0169:             * from versioning and can add their own children without the usual
0170:             * exception that would normally be thrown when the component hierarchy is
0171:             * modified during rendering.
0172:             * 
0173:             * @param component
0174:             *            The component to add
0175:             * @return True, if component has been added
0176:             */
0177:            public final boolean autoAdd(final Component component) {
0178:                if (component == null) {
0179:                    throw new IllegalArgumentException(
0180:                            "argument component may not be null");
0181:                }
0182:
0183:                /* Replace strategy */
0184:                if (get(component.getId()) != null) {
0185:                    this .remove(component);
0186:                }
0187:                component.setAuto(true);
0188:                add(component);
0189:                component.internalAttach();
0190:                component.render();
0191:                return true;
0192:            }
0193:
0194:            /**
0195:             * @param component
0196:             *            The component to check
0197:             * @param recurse
0198:             *            True if all descendents should be considered
0199:             * @return True if the component is contained in this container
0200:             */
0201:            public final boolean contains(final Component component,
0202:                    final boolean recurse) {
0203:                if (component == null) {
0204:                    throw new IllegalArgumentException(
0205:                            "argument component may not be null");
0206:                }
0207:
0208:                if (recurse) {
0209:                    // Start at component and continue while we're not out of parents
0210:                    for (Component current = component; current != null;) {
0211:                        // Get parent
0212:                        final MarkupContainer parent = current.getParent();
0213:
0214:                        // If this container is the parent, then the component is
0215:                        // recursively contained by this container
0216:                        if (parent == this ) {
0217:                            // Found it!
0218:                            return true;
0219:                        }
0220:
0221:                        // Move up the chain to the next parent
0222:                        current = parent;
0223:                    }
0224:
0225:                    // Failed to find this container in component's ancestry
0226:                    return false;
0227:                } else {
0228:                    // Is the component contained in this container?
0229:                    return component.getParent() == this ;
0230:                }
0231:            }
0232:
0233:            /**
0234:             * Get a child component by looking it up with the given path.
0235:             * 
0236:             * @param path
0237:             *            Path to component
0238:             * @return The component at the path
0239:             */
0240:            public final Component get(final String path) {
0241:                // Reference to this container
0242:                if (path == null || path.trim().equals("")) {
0243:                    return this ;
0244:                }
0245:
0246:                // Get child's id, if any
0247:                final String id = Strings.firstPathComponent(path,
0248:                        Component.PATH_SEPARATOR);
0249:
0250:                // Get child by id
0251:                Component child = children_get(id);
0252:
0253:                // If the container is transparent, than ask its parent.
0254:                // ParentResolver does something quite similar, but because of <head>,
0255:                // <body>, <wicket:panel> etc. it is quite common to have transparent
0256:                // components. Hence, this is little short cut for a tiny performance
0257:                // optimization.
0258:                if ((child == null) && isTransparentResolver()
0259:                        && (getParent() != null)) {
0260:                    // Special tags like "_body", "_panel" must implement IComponentResolver
0261:                    // if they want to be transparent.
0262:                    if (path.startsWith("_") == false) {
0263:                        child = getParent().get(path);
0264:                    }
0265:                }
0266:
0267:                // Found child?
0268:                final String path2 = Strings.afterFirstPathComponent(path,
0269:                        Component.PATH_SEPARATOR);
0270:                if (child != null) {
0271:                    // Recurse on latter part of path
0272:                    return child.get(path2);
0273:                }
0274:
0275:                return child;
0276:            }
0277:
0278:            /**
0279:             * Get the type of associated markup for this component.
0280:             * 
0281:             * @return The type of associated markup for this component (for example,
0282:             *         "html", "wml" or "vxml"). The markup type for a component is
0283:             *         independent of whether or not the component actually has an
0284:             *         associated markup resource file (which is determined at runtime).
0285:             *         If there is no markup type for a component, null may be returned,
0286:             *         but this means that no markup can be loaded for the class.
0287:             */
0288:            public String getMarkupType() {
0289:                throw new IllegalStateException(
0290:                        exceptionMessage("You cannot directly subclass Page or MarkupContainer.	 Instead, subclass a markup-specific class, such as WebPage or WebMarkupContainer"));
0291:            }
0292:
0293:            /**
0294:             * THIS METHOD IS NOT PART OF THE WICKET PUBLIC API. DO NOT USE IT.
0295:             * 
0296:             * Adds a child component to this container.
0297:             * 
0298:             * @param child
0299:             *            The child
0300:             * @throws IllegalArgumentException
0301:             *             Thrown if a child with the same id is replaced by the add
0302:             *             operation.
0303:             */
0304:            public void internalAdd(final Component child) {
0305:                if (log.isDebugEnabled()) {
0306:                    log.debug("internalAdd " + child.getId() + " to " + this );
0307:                }
0308:
0309:                // Add to map
0310:                addedComponent(child);
0311:                put(child);
0312:            }
0313:
0314:            /**
0315:             * THIS METHOD IS NOT PART OF THE WICKET PUBLIC API. DO NOT CALL OR
0316:             * OVERRIDE.
0317:             * 
0318:             * Called when a request begins.
0319:             */
0320:            public void internalAttach() {
0321:                // Handle begin request for the container itself
0322:                try {
0323:                    super .internalAttach();
0324:
0325:                    // Loop through child components
0326:                    final int size = children_size();
0327:                    for (int i = 0; i < size; i++) {
0328:                        // Get next child
0329:                        final Component child = children_get(i);
0330:
0331:                        // Ignore feedback as that was done in Page
0332:                        if (!(child instanceof  IFeedback)) {
0333:                            // Call begin request on the child
0334:                            child.internalAttach();
0335:                        }
0336:                    }
0337:                } catch (RuntimeException ex) {
0338:                    if (ex instanceof  WicketRuntimeException)
0339:                        throw ex;
0340:                    else
0341:                        throw new WicketRuntimeException(
0342:                                "Error attaching this container for rendering: "
0343:                                        + this , ex);
0344:                }
0345:            }
0346:
0347:            /**
0348:             * THIS METHOD IS NOT PART OF THE WICKET PUBLIC API. DO NOT CALL OR
0349:             * OVERRIDE.
0350:             * 
0351:             * Called when a request ends.
0352:             */
0353:            public void internalDetach() {
0354:                // Handle end request for the container itself
0355:                super .internalDetach();
0356:
0357:                // Loop through child components
0358:                final Iterator iter = iterator();
0359:                while (iter.hasNext()) {
0360:                    // Get next child
0361:                    final Component child = (Component) iter.next();
0362:
0363:                    // Call end request on the child
0364:                    child.internalDetach();
0365:                }
0366:            }
0367:
0368:            /**
0369:             * @return Iterator that iterates through children in the order they were
0370:             *         added
0371:             */
0372:            public final Iterator iterator() {
0373:                return new Iterator() {
0374:                    int index = 0;
0375:
0376:                    public boolean hasNext() {
0377:                        return index < children_size();
0378:                    }
0379:
0380:                    public Object next() {
0381:                        return children_get(index++);
0382:                    }
0383:
0384:                    public void remove() {
0385:                        removedComponent(children_remove(--index));
0386:                    }
0387:                };
0388:            }
0389:
0390:            /**
0391:             * @param comparator
0392:             *            The comparator
0393:             * @return Iterator that iterates over children in the order specified by
0394:             *         comparator
0395:             */
0396:            public final Iterator iterator(Comparator comparator) {
0397:                final List sorted;
0398:                if (children == null) {
0399:                    sorted = Collections.EMPTY_LIST;
0400:                } else {
0401:                    if (children instanceof  Component) {
0402:                        sorted = new ArrayList(1);
0403:                        sorted.add(children);
0404:                    } else {
0405:                        sorted = Arrays.asList((Component[]) children);
0406:                    }
0407:                }
0408:                Collections.sort(sorted, comparator);
0409:                return sorted.iterator();
0410:            }
0411:
0412:            /**
0413:             * @param component
0414:             *            Component to remove from this container
0415:             */
0416:            public void remove(final Component component) {
0417:                if (component == null) {
0418:                    throw new IllegalArgumentException(
0419:                            "argument component may not be null");
0420:                }
0421:
0422:                children_remove(component);
0423:                removedComponent(component);
0424:            }
0425:
0426:            /**
0427:             * Removes the given component
0428:             * 
0429:             * @param id
0430:             *            The id of the component to remove
0431:             */
0432:            public final void remove(final String id) {
0433:                if (id == null) {
0434:                    throw new IllegalArgumentException(
0435:                            "argument id may not be null");
0436:                }
0437:
0438:                final Component component = get(id);
0439:                if (component != null) {
0440:                    remove(component);
0441:                } else {
0442:                    throw new WicketRuntimeException(
0443:                            "Unable to find a component with id '" + id
0444:                                    + "' to remove");
0445:                }
0446:            }
0447:
0448:            /**
0449:             * Removes all children from this container.
0450:             * <p>
0451:             * Note: implementation does not call
0452:             * {@link MarkupContainer#remove(Component) } for each component.
0453:             */
0454:            public final void removeAll() {
0455:                if (children != null) {
0456:                    addStateChange(new Change() {
0457:                        private static final long serialVersionUID = 1L;
0458:
0459:                        final Object removedChildren = MarkupContainer.this .children;
0460:
0461:                        public void undo() {
0462:                            MarkupContainer.this .children = removedChildren;
0463:                            int size = children_size();
0464:                            for (int i = 0; i < size; i++) {
0465:                                // Get next child
0466:                                final Component child = children_get(i);
0467:                                child.setParent(MarkupContainer.this );
0468:                            }
0469:                        }
0470:
0471:                        public String toString() {
0472:                            return "RemoveAllChange[component: " + getPath()
0473:                                    + ", removed Children: " + removedChildren
0474:                                    + "]";
0475:                        }
0476:                    });
0477:
0478:                    // Loop through child components
0479:                    int size = children_size();
0480:                    for (int i = 0; i < size; i++) {
0481:                        // Get next child
0482:                        final Component child = children_get(i);
0483:
0484:                        // Do not call remove() because the state change would than be
0485:                        // recorded twice.
0486:                        child.detachModel();
0487:                        child.setParent(null);
0488:                    }
0489:
0490:                    this .children = null;
0491:                }
0492:            }
0493:
0494:            /**
0495:             * Renders the entire associated markup stream for a container such as a
0496:             * Border or Panel. Any leading or trailing raw markup in the associated
0497:             * markup is skipped.
0498:             * 
0499:             * @param openTagName
0500:             *            the tag to render the associated markup for
0501:             * @param exceptionMessage
0502:             *            message that will be used for exceptions
0503:             */
0504:            public final void renderAssociatedMarkup(final String openTagName,
0505:                    final String exceptionMessage) {
0506:                // Get markup associated with Border or Panel component
0507:                final MarkupStream originalMarkupStream = getMarkupStream();
0508:                final MarkupStream associatedMarkupStream = getAssociatedMarkupStream(true);
0509:
0510:                // skip until the targetted tag is found
0511:                associatedMarkupStream.skipUntil(openTagName);
0512:                setMarkupStream(associatedMarkupStream);
0513:
0514:                // Get open tag in associated markup of border component
0515:                final ComponentTag associatedMarkupOpenTag = associatedMarkupStream
0516:                        .getTag();
0517:
0518:                // Check for required open tag name
0519:                if (!((associatedMarkupOpenTag != null)
0520:                        && associatedMarkupOpenTag.isOpen() && (associatedMarkupOpenTag instanceof  WicketTag))) {
0521:                    associatedMarkupStream
0522:                            .throwMarkupException(exceptionMessage);
0523:                }
0524:
0525:                try {
0526:                    setIgnoreAttributeModifier(true);
0527:                    renderComponentTag(associatedMarkupOpenTag);
0528:                    associatedMarkupStream.next();
0529:                    renderComponentTagBody(associatedMarkupStream,
0530:                            associatedMarkupOpenTag);
0531:                    renderClosingComponentTag(associatedMarkupStream,
0532:                            associatedMarkupOpenTag, false);
0533:                    setMarkupStream(originalMarkupStream);
0534:                } finally {
0535:                    setIgnoreAttributeModifier(false);
0536:                }
0537:            }
0538:
0539:            /**
0540:             * Replaces a child component of this container with another
0541:             * 
0542:             * @param child
0543:             *            The child
0544:             * @throws IllegalArgumentException
0545:             *             Thrown if there was no child with the same id.
0546:             * @return This
0547:             */
0548:            public final MarkupContainer replace(final Component child) {
0549:                if (child == null) {
0550:                    throw new IllegalArgumentException(
0551:                            "argument child must be not null");
0552:                }
0553:
0554:                if (log.isDebugEnabled()) {
0555:                    log.debug("Replacing " + child.getId() + " in " + this );
0556:                }
0557:
0558:                if (child.getParent() != this ) {
0559:                    // Add to map
0560:                    final Component replaced = put(child);
0561:
0562:                    // Look up to make sure it was already in the map
0563:                    if (replaced == null) {
0564:                        throw new WicketRuntimeException(
0565:                                exceptionMessage("Cannot replace a component which has not been added: id='"
0566:                                        + child.getId()
0567:                                        + "', component="
0568:                                        + child));
0569:                    }
0570:
0571:                    // first remove the component.
0572:                    removedComponent(replaced);
0573:                    // then add the other one.
0574:                    addedComponent(child);
0575:
0576:                    // The position of the associated markup remains the same
0577:                    child.markupIndex = replaced.markupIndex;
0578:                }
0579:
0580:                return this ;
0581:            }
0582:
0583:            /**
0584:             * @see wicket.Component#setModel(wicket.model.IModel)
0585:             */
0586:            public Component setModel(final IModel model) {
0587:                final IModel previous = getModel();
0588:                super .setModel(model);
0589:                if (previous instanceof  ICompoundModel) {
0590:                    visitChildren(new IVisitor() {
0591:
0592:                        public Object component(Component component) {
0593:                            IModel compModel = component.getModel();
0594:                            if (compModel == previous) {
0595:                                component.setModel(null);
0596:                            } else if (compModel == model) {
0597:                                component.modelChanged();
0598:                            }
0599:                            return IVisitor.CONTINUE_TRAVERSAL;
0600:                        }
0601:
0602:                    });
0603:                }
0604:                return this ;
0605:            }
0606:
0607:            /**
0608:             * Get the number of children in this container.
0609:             * 
0610:             * @return Number of children in this container
0611:             */
0612:            public final int size() {
0613:                return children_size();
0614:            }
0615:
0616:            /**
0617:             * @see wicket.Component#toString()
0618:             */
0619:            public String toString() {
0620:                return toString(false);
0621:            }
0622:
0623:            /**
0624:             * @param detailed
0625:             *            True if a detailed string is desired
0626:             * @return String representation of this container
0627:             */
0628:            public String toString(final boolean detailed) {
0629:                final StringBuffer buffer = new StringBuffer();
0630:                buffer.append("[MarkupContainer ");
0631:                buffer.append(super .toString(true));
0632:                if (detailed) {
0633:                    if (getMarkupStream() != null) {
0634:                        buffer.append(", markupStream = " + getMarkupStream());
0635:                    }
0636:
0637:                    if (children_size() != 0) {
0638:                        buffer.append(", children = ");
0639:
0640:                        // Loop through child components
0641:                        final int size = children_size();
0642:                        for (int i = 0; i < size; i++) {
0643:                            // Get next child
0644:                            final Component child = children_get(i);
0645:                            if (i != 0) {
0646:                                buffer.append(' ');
0647:                            }
0648:                            buffer.append(child.toString());
0649:                        }
0650:                    }
0651:                }
0652:                buffer.append(']');
0653:                return buffer.toString();
0654:            }
0655:
0656:            /**
0657:             * Traverses all child components of the given class in this container,
0658:             * calling the visitor's visit method at each one.
0659:             * 
0660:             * @param clazz
0661:             *            The class of child to visit, or null to visit all children
0662:             * @param visitor
0663:             *            The visitor to call back to
0664:             * @return The return value from a visitor which halted the traversal, or
0665:             *         null if the entire traversal occurred
0666:             */
0667:            public final Object visitChildren(final Class clazz,
0668:                    final IVisitor visitor) {
0669:                if (visitor == null) {
0670:                    throw new IllegalArgumentException(
0671:                            "argument visitor may not be null");
0672:                }
0673:
0674:                // Iterate through children of this container
0675:                for (int i = 0; i < children_size(); i++) {
0676:                    // Get next child component
0677:                    final Component child = children_get(i);
0678:                    Object value = null;
0679:
0680:                    // Is the child of the correct class (or was no class specified)?
0681:                    if (clazz == null || clazz.isInstance(child)) {
0682:                        // Call visitor
0683:                        value = visitor.component(child);
0684:
0685:                        // If visitor returns a non-null value, it halts the traversal
0686:                        if ((value != IVisitor.CONTINUE_TRAVERSAL)
0687:                                && (value != IVisitor.CONTINUE_TRAVERSAL_BUT_DONT_GO_DEEPER)) {
0688:                            return value;
0689:                        }
0690:                    }
0691:
0692:                    // If child is a container
0693:                    if ((child instanceof  MarkupContainer)
0694:                            && (value != IVisitor.CONTINUE_TRAVERSAL_BUT_DONT_GO_DEEPER)) {
0695:                        // visit the children in the container
0696:                        value = ((MarkupContainer) child).visitChildren(clazz,
0697:                                visitor);
0698:
0699:                        // If visitor returns a non-null value, it halts the traversal
0700:                        if ((value != IVisitor.CONTINUE_TRAVERSAL)
0701:                                && (value != IVisitor.CONTINUE_TRAVERSAL_BUT_DONT_GO_DEEPER)) {
0702:                            return value;
0703:                        }
0704:                    }
0705:                }
0706:
0707:                return null;
0708:            }
0709:
0710:            /**
0711:             * Traverses all child components in this container, calling the visitor's
0712:             * visit method at each one.
0713:             * 
0714:             * @param visitor
0715:             *            The visitor to call back to
0716:             * @return The return value from a visitor which halted the traversal, or
0717:             *         null if the entire traversal occurred
0718:             */
0719:            public final Object visitChildren(final IVisitor visitor) {
0720:                return visitChildren(null, visitor);
0721:            }
0722:
0723:            /**
0724:             * Get the markup stream for this component.
0725:             * 
0726:             * @return The markup stream for this component, or if it doesn't have one,
0727:             *         the markup stream for the nearest parent which does have one
0728:             */
0729:            protected final MarkupStream findMarkupStream() {
0730:                // Start here
0731:                MarkupContainer c = this ;
0732:
0733:                // Walk up hierarchy until markup found
0734:                while (c.getMarkupStream() == null) {
0735:                    // Check parent
0736:                    c = c.getParent();
0737:
0738:                    // Are we at the top of the hierarchy?
0739:                    if (c == null) {
0740:                        // Failed to find markup stream
0741:                        throw new WicketRuntimeException(
0742:                                exceptionMessage("No markup found"));
0743:                    }
0744:                }
0745:
0746:                return c.getMarkupStream();
0747:            }
0748:
0749:            /**
0750:             * Gets a fresh markup stream that contains the (immutable) markup resource
0751:             * for this class.
0752:             * 
0753:             * @param throwException
0754:             *            If true, throw an exception, if markup could not be found
0755:             * @return A stream of MarkupElement elements
0756:             */
0757:            public final MarkupStream getAssociatedMarkupStream(
0758:                    final boolean throwException) {
0759:                try {
0760:                    return getApplication().getMarkupCache().getMarkupStream(
0761:                            this , throwException);
0762:                } catch (MarkupException ex) {
0763:                    // re-throw it. The exception contains already all the information
0764:                    // required.
0765:                    throw ex;
0766:                } catch (WicketRuntimeException ex) {
0767:                    // throw exception since there is no associated markup
0768:                    throw new MarkupNotFoundException(
0769:                            exceptionMessage("Markup of type '"
0770:                                    + getMarkupType()
0771:                                    + "' for component '"
0772:                                    + getClass().getName()
0773:                                    + "' not found."
0774:                                    + " Enable debug messages for wicket.util.resource to get a list of all filenames tried"),
0775:                            ex);
0776:                }
0777:            }
0778:
0779:            /**
0780:             * Create a new markup resource stream for the container.
0781:             * <p>
0782:             * Note: it will only called once, the IResourceStream will be cached by
0783:             * MarkupCache.
0784:             * <p>
0785:             * Note: IResourceStreamLocators should be used in case the strategy to find
0786:             * a markup resource should be extended for ALL components of your
0787:             * application.
0788:             * 
0789:             * @see wicket.util.resource.locator.IResourceStreamLocator
0790:             * @see wicket.markup.MarkupCache
0791:             * 
0792:             * @param containerClass
0793:             *            The container the markup should be associated with
0794:             * @return A IResourceStream if the resource was found
0795:             */
0796:            public IResourceStream newMarkupResourceStream(Class containerClass) {
0797:                // Get locator to search for the resource
0798:                final IResourceStreamLocator locator = getApplication()
0799:                        .getResourceSettings().getResourceStreamLocator();
0800:
0801:                // Markup is associated with the containers class. Walk up the class
0802:                // hierarchy up to MarkupContainer to find the containers markup
0803:                // resource.
0804:                while (containerClass != MarkupContainer.class) {
0805:                    final IResourceStream resourceStream = locator.locate(
0806:                            containerClass, containerClass.getName().replace(
0807:                                    '.', '/'), getStyle(), getLocale(),
0808:                            getMarkupType());
0809:
0810:                    // Did we find it already?
0811:                    if (resourceStream != null) {
0812:                        return new MarkupResourceStream(resourceStream,
0813:                                new ContainerInfo(this ), containerClass);
0814:                    }
0815:
0816:                    // Walk up the class hierarchy one level, if markup has not
0817:                    // yet been found
0818:                    containerClass = containerClass.getSuperclass();
0819:                }
0820:
0821:                return null;
0822:            }
0823:
0824:            /**
0825:             * Get the markup stream set on this container.
0826:             * 
0827:             * @return Returns the markup stream set on this container.
0828:             */
0829:            public final MarkupStream getMarkupStream() {
0830:                return markupStream;
0831:            }
0832:
0833:            /**
0834:             * Handle the container's body. If your override of this method does not
0835:             * advance the markup stream to the close tag for the openTag, a runtime
0836:             * exception will be thrown by the framework.
0837:             * 
0838:             * @param markupStream
0839:             *            The markup stream
0840:             * @param openTag
0841:             *            The open tag for the body
0842:             */
0843:            protected void onComponentTagBody(final MarkupStream markupStream,
0844:                    final ComponentTag openTag) {
0845:                renderComponentTagBody(markupStream, openTag);
0846:            }
0847:
0848:            /**
0849:             * Renders this component. This implementation just calls renderComponent.
0850:             * 
0851:             * @param markupStream
0852:             */
0853:            protected void onRender(final MarkupStream markupStream) {
0854:                renderComponent(markupStream);
0855:            }
0856:
0857:            /**
0858:             * Renders this component and all sub-components using the given markup
0859:             * stream.
0860:             * 
0861:             * @param markupStream
0862:             *            The markup stream
0863:             */
0864:            protected void renderAll(final MarkupStream markupStream) {
0865:                // Loop through the markup in this container
0866:                while (markupStream.hasMore()) {
0867:                    // Element rendering is responsible for advancing markup stream!
0868:                    final int index = markupStream.getCurrentIndex();
0869:                    renderNext(markupStream);
0870:                    if (index == markupStream.getCurrentIndex()) {
0871:                        markupStream
0872:                                .throwMarkupException("Component at markup stream index "
0873:                                        + index
0874:                                        + " failed to advance the markup stream");
0875:                    }
0876:                }
0877:            }
0878:
0879:            /**
0880:             * Renders markup for the body of a ComponentTag from the current position
0881:             * in the given markup stream. If the open tag passed in does not require a
0882:             * close tag, nothing happens. Markup is rendered until the closing tag for
0883:             * openTag is reached.
0884:             * 
0885:             * @param markupStream
0886:             *            The markup stream
0887:             * @param openTag
0888:             *            The open tag
0889:             */
0890:            protected final void renderComponentTagBody(
0891:                    final MarkupStream markupStream, final ComponentTag openTag) {
0892:                // If the open tag requires a close tag
0893:                boolean render = openTag.requiresCloseTag();
0894:                if (render == false) {
0895:                    // Tags like <p> do not require a close tag, but they may have.
0896:                    render = !openTag.hasNoCloseTag();
0897:                }
0898:                if (render == true) {
0899:                    // Loop through the markup in this container
0900:                    while (markupStream.hasMore()
0901:                            && !markupStream.get().closes(openTag)) {
0902:                        // Render markup element. Doing so must advance the markup
0903:                        // stream
0904:                        final int index = markupStream.getCurrentIndex();
0905:                        renderNext(markupStream);
0906:                        if (index == markupStream.getCurrentIndex()) {
0907:                            markupStream
0908:                                    .throwMarkupException("Markup element at index "
0909:                                            + index
0910:                                            + " failed to advance the markup stream");
0911:                        }
0912:                    }
0913:                }
0914:            }
0915:
0916:            /**
0917:             * Set markup stream for this container.
0918:             * 
0919:             * @param markupStream
0920:             *            The markup stream
0921:             */
0922:            protected final void setMarkupStream(final MarkupStream markupStream) {
0923:                this .markupStream = markupStream;
0924:            }
0925:
0926:            /**
0927:             * @return True if this markup container has associated markup
0928:             */
0929:            final boolean hasAssociatedMarkup() {
0930:                return getApplication().getMarkupCache().hasAssociatedMarkup(
0931:                        this );
0932:            }
0933:
0934:            /**
0935:             * @param component
0936:             *            Component being added
0937:             */
0938:            private final void addedComponent(final Component component) {
0939:                // Check for degenerate case
0940:                if (component == this ) {
0941:                    throw new IllegalArgumentException(
0942:                            "Component can't be added to itself");
0943:                }
0944:
0945:                MarkupContainer parent = component.getParent();
0946:                if (parent != null) {
0947:                    parent.remove(component);
0948:                }
0949:
0950:                // Set child's parent
0951:                component.setParent(this );
0952:
0953:                // Tell the page a component was added
0954:                final Page page = findPage();
0955:                if (page != null) {
0956:                    page.componentAdded(component);
0957:                }
0958:            }
0959:
0960:            /**
0961:             * @param child
0962:             *            Child to add
0963:             */
0964:            private final void children_add(final Component child) {
0965:                if (this .children == null) {
0966:                    this .children = child;
0967:                } else {
0968:                    // Get current list size
0969:                    final int size = children_size();
0970:
0971:                    // Create array that holds size + 1 elements
0972:                    final Component[] children = new Component[size + 1];
0973:
0974:                    // Loop through existing children copying them
0975:                    for (int i = 0; i < size; i++) {
0976:                        children[i] = children_get(i);
0977:                    }
0978:
0979:                    // Add new child to the end
0980:                    children[size] = child;
0981:
0982:                    // Save new children
0983:                    this .children = children;
0984:                }
0985:            }
0986:
0987:            private final Component children_get(int index) {
0988:                if (index == 0) {
0989:                    if (children instanceof  Component) {
0990:                        return (Component) children;
0991:                    } else {
0992:                        return ((Component[]) children)[index];
0993:                    }
0994:                } else {
0995:                    return ((Component[]) children)[index];
0996:                }
0997:            }
0998:
0999:            private final Component children_get(final String id) {
1000:                if (children instanceof  Component) {
1001:                    final Component component = (Component) children;
1002:                    if (component.getId().equals(id)) {
1003:                        return component;
1004:                    }
1005:                } else {
1006:                    if (children != null) {
1007:                        final Component[] components = (Component[]) children;
1008:                        for (int i = 0; i < components.length; i++) {
1009:                            if (components[i].getId().equals(id)) {
1010:                                return components[i];
1011:                            }
1012:                        }
1013:                    }
1014:                }
1015:                return null;
1016:            }
1017:
1018:            private final int children_indexOf(Component child) {
1019:                if (children instanceof  Component) {
1020:                    if (((Component) children).getId().equals(child.getId())) {
1021:                        return 0;
1022:                    }
1023:                } else {
1024:                    if (children != null) {
1025:                        final Component[] components = (Component[]) children;
1026:                        for (int i = 0; i < components.length; i++) {
1027:                            if (components[i].getId().equals(child.getId())) {
1028:                                return i;
1029:                            }
1030:                        }
1031:                    }
1032:                }
1033:                return -1;
1034:            }
1035:
1036:            private final Component children_remove(Component component) {
1037:                int index = children_indexOf(component);
1038:                if (index != -1) {
1039:                    return children_remove(index);
1040:                }
1041:                return null;
1042:            }
1043:
1044:            private final Component children_remove(int index) {
1045:                if (children instanceof  Component) {
1046:                    if (index == 0) {
1047:                        final Component removed = (Component) children;
1048:                        this .children = null;
1049:                        return removed;
1050:                    } else {
1051:                        throw new IndexOutOfBoundsException();
1052:                    }
1053:                } else {
1054:                    Component[] c = ((Component[]) children);
1055:                    final Component removed = c[index];
1056:                    if (c.length == 2) {
1057:                        if (index == 0) {
1058:                            this .children = c[1];
1059:                        } else if (index == 1) {
1060:                            this .children = c[0];
1061:                        } else {
1062:                            throw new IndexOutOfBoundsException();
1063:                        }
1064:                    } else {
1065:                        Component[] newChildren = new Component[c.length - 1];
1066:                        int j = 0;
1067:                        for (int i = 0; i < c.length; i++) {
1068:                            if (i != index) {
1069:                                newChildren[j++] = c[i];
1070:                            }
1071:                        }
1072:                        this .children = newChildren;
1073:                    }
1074:                    return removed;
1075:                }
1076:            }
1077:
1078:            private final Component children_set(int index, Component child) {
1079:                final Component replaced;
1080:                if (index < children_size()) {
1081:                    if (children == null || children instanceof  Component) {
1082:                        replaced = (Component) children;
1083:                        children = child;
1084:                    } else {
1085:                        final Component[] children = (Component[]) this .children;
1086:                        replaced = children[index];
1087:                        children[index] = child;
1088:                    }
1089:                } else {
1090:                    throw new IndexOutOfBoundsException();
1091:                }
1092:                return replaced;
1093:            }
1094:
1095:            private final int children_size() {
1096:                if (children == null) {
1097:                    return 0;
1098:                } else {
1099:                    if (children instanceof  Component) {
1100:                        return 1;
1101:                    }
1102:                    return ((Component[]) children).length;
1103:                }
1104:            }
1105:
1106:            /**
1107:             * Ensure that there is space in childForId map for a new entry before
1108:             * adding it.
1109:             * 
1110:             * @param child
1111:             *            The child to put into the map
1112:             * @return Any component that was replaced
1113:             */
1114:            private final Component put(final Component child) {
1115:                int index = children_indexOf(child);
1116:                if (index == -1) {
1117:                    children_add(child);
1118:                    return null;
1119:                } else {
1120:                    return children_set(index, child);
1121:                }
1122:            }
1123:
1124:            /**
1125:             * @param component
1126:             *            Component being removed
1127:             */
1128:            private final void removedComponent(final Component component) {
1129:                // Notify Page that component is being removed
1130:                final Page page = component.findPage();
1131:                if (page != null) {
1132:                    page.componentRemoved(component);
1133:                }
1134:
1135:                // detach children models
1136:                if (component instanceof  MarkupContainer) {
1137:                    ((MarkupContainer) component).visitChildren(new IVisitor() {
1138:                        public Object component(Component component) {
1139:                            try {
1140:                                // detach any models of the component
1141:                                component.detachModels();
1142:                            } catch (Exception e) // catch anything; we MUST detach all
1143:                            // models
1144:                            {
1145:                                log.error("detaching models of component "
1146:                                        + component + " failed:", e);
1147:                            }
1148:                            return IVisitor.CONTINUE_TRAVERSAL;
1149:                        }
1150:                    });
1151:                }
1152:
1153:                // Detach model
1154:                component.detachModels();
1155:                // Component is removed
1156:                component.setParent(null);
1157:            }
1158:
1159:            /**
1160:             * Renders the next element of markup in the given markup stream.
1161:             * 
1162:             * @param markupStream
1163:             *            The markup stream
1164:             */
1165:            private final void renderNext(final MarkupStream markupStream) {
1166:                // Get the current markup element
1167:                final MarkupElement element = markupStream.get();
1168:
1169:                // If it a tag like <wicket..> or <span wicket:id="..." >
1170:                if ((element instanceof  ComponentTag)
1171:                        && !markupStream.atCloseTag()) {
1172:                    // Get element as tag
1173:                    final ComponentTag tag = (ComponentTag) element;
1174:
1175:                    // Get component id
1176:                    final String id = tag.getId();
1177:
1178:                    // Get the component for the id from the given container
1179:                    final Component component = get(id);
1180:
1181:                    // Failed to find it?
1182:                    if (component != null) {
1183:                        component.render(markupStream);
1184:                    } else {
1185:                        // 2rd try: Components like Border and Panel might implement
1186:                        // the ComponentResolver interface as well.
1187:                        MarkupContainer container = this ;
1188:                        while (container != null) {
1189:                            if (container instanceof  IComponentResolver) {
1190:                                if (((IComponentResolver) container).resolve(
1191:                                        this , markupStream, tag)) {
1192:                                    return;
1193:                                }
1194:                            }
1195:
1196:                            container = container
1197:                                    .findParent(MarkupContainer.class);
1198:                        }
1199:
1200:                        // 3rd try: Try application's component resolvers
1201:                        final List componentResolvers = this .getApplication()
1202:                                .getPageSettings().getComponentResolvers();
1203:                        final Iterator iterator = componentResolvers.iterator();
1204:                        while (iterator.hasNext()) {
1205:                            final IComponentResolver resolver = (IComponentResolver) iterator
1206:                                    .next();
1207:                            if (resolver.resolve(this , markupStream, tag)) {
1208:                                return;
1209:                            }
1210:                        }
1211:
1212:                        if (tag instanceof  WicketTag) {
1213:                            if (((WicketTag) tag).isChildTag()) {
1214:                                markupStream.throwMarkupException("Found "
1215:                                        + tag.toString()
1216:                                        + " but no <wicket:extend>");
1217:                            } else {
1218:                                markupStream
1219:                                        .throwMarkupException("Failed to handle: "
1220:                                                + tag.toString());
1221:                            }
1222:                        }
1223:
1224:                        // No one was able to handle the component id
1225:                        markupStream
1226:                                .throwMarkupException("Unable to find component with id '"
1227:                                        + id
1228:                                        + "' in "
1229:                                        + this 
1230:                                        + ". This means that you declared wicket:id="
1231:                                        + id
1232:                                        + " in your markup, but that you either did not add the "
1233:                                        + "component to your page at all, or that the hierarchy does not match.");
1234:                    }
1235:                } else {
1236:                    // Render as raw markup
1237:                    if (log.isDebugEnabled()) {
1238:                        log.debug("Rendering raw markup");
1239:                    }
1240:                    getResponse().write(element.toCharSequence());
1241:                    markupStream.next();
1242:                }
1243:            }
1244:
1245:            /**
1246:             * Some MarkupContainers (e.g. HtmlHeaderContainer, BodyOnLoadContainer)
1247:             * have to be transparent with respect to there child components. A
1248:             * transparent container gets its children from its parent container.
1249:             * <p>
1250:             * 
1251:             * @see wicket.markup.resolver.ParentResolver
1252:             * 
1253:             * @return false. By default a MarkupContainer is not transparent.
1254:             */
1255:            public boolean isTransparentResolver() {
1256:                return false;
1257:            }
1258:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.