001/*
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements.  See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache License, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License.  You may obtain a copy of the License at
008 *
009 *      http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017package org.apache.wicket.feedback;
018
019import java.util.ArrayList;
020import java.util.List;
021
022import org.apache.wicket.Component;
023import org.apache.wicket.MarkupContainer;
024import org.apache.wicket.Session;
025import org.apache.wicket.util.visit.IVisit;
026import org.apache.wicket.util.visit.IVisitor;
027
028/**
029 * Collects feedback messages from all the places where they can be stored.
030 * 
031 * @author igor
032 */
033public class FeedbackCollector
034{
035        private final Component component;
036        private boolean includeSession = true;
037        private boolean recursive = true;
038
039        /**
040         * Constructs a collector that will only collect messages from {@link Session}. To collect
041         * messages from session and components use {@link #FeedbackCollector(Component, boolean)}.
042         */
043        public FeedbackCollector()
044        {
045                this(null, true);
046        }
047
048        /**
049         * Constructs a collector that will collect messages from the specified
050         * {@code container}
051         * 
052         * @param component
053         *            root component from which feedback will be collected
054         */
055        public FeedbackCollector(Component component)
056        {
057                this(component, false);
058        }
059
060        /**
061         * Constructs a collector that will collect messages from {@link Session} and specified
062         * {@code container}
063         *
064         * @param component
065         *            root component from which feedback will be collected
066         * @param includeSession
067         *            controls whether or not feedback from the {@link Session} will be collected
068         */
069        public FeedbackCollector(Component component, boolean includeSession)
070        {
071                this.component = component;
072                this.includeSession = includeSession;
073        }
074
075        /**
076         * Controls whether or not feedback from the {@link Session} will be collected
077         * 
078         * See {@link Session#getFeedbackMessages}
079         * 
080         * @param value
081         * @return {@code this} for chaining
082         */
083        public final FeedbackCollector setIncludeSession(boolean value)
084        {
085                includeSession = value;
086                return this;
087        }
088
089        /**
090         * Controls whether or not feedback will be collected recursively from the descendants of the
091         * specified component.
092         * 
093         * @param value
094         * @return {@code this} for chaining
095         */
096        public final FeedbackCollector setRecursive(boolean value)
097        {
098                recursive = value;
099                return this;
100        }
101
102        /**
103         * Collects all feedback messages
104         * 
105         * @return a {@link List} of collected messages
106         */
107        public final List<FeedbackMessage> collect()
108        {
109                return collect(IFeedbackMessageFilter.ALL);
110        }
111
112        /**
113         * Collects all feedback messages that match the specified {@code filter}
114         * 
115         * @param filter
116         * @return a {@link List} of collected messages
117         */
118        public final List<FeedbackMessage> collect(final IFeedbackMessageFilter filter)
119        {
120                final List<FeedbackMessage> messages = new ArrayList<>();
121
122                if (includeSession && Session.exists())
123                {
124                        messages.addAll(Session.get().getFeedbackMessages().messages(filter));
125                }
126
127                if (component != null && component.hasFeedbackMessage())
128                {
129                        messages.addAll(component.getFeedbackMessages().messages(filter));
130                }
131
132                if (component != null && recursive && component instanceof MarkupContainer)
133                {
134                        ((MarkupContainer)component).visitChildren(new IVisitor<Component, Void>()
135                        {
136                                @Override
137                                public void component(Component object, IVisit<Void> visit)
138                                {
139                                        if (!shouldRecurseInto(object))
140                                        {
141                                                visit.dontGoDeeper();
142                                                return;
143                                        }
144
145                                        if (object.hasFeedbackMessage())
146                                        {
147                                                messages.addAll(object.getFeedbackMessages().messages(filter));
148                                        }
149                                }
150                        });
151                }
152
153                return messages;
154        }
155
156        /**
157         * Determines whether or not recursive message collection should continue into the specified
158         * component. If returning {@code false} feedback messages from the specified component nor any
159         * of its children will be included.
160         * 
161         * @param component
162         * @return
163         */
164        protected boolean shouldRecurseInto(Component component)
165        {
166                return true;
167        }
168}