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.io.Serializable;
020import java.util.Collections;
021import java.util.Comparator;
022import java.util.List;
023
024import org.apache.wicket.Component;
025import org.apache.wicket.Page;
026import org.apache.wicket.Session;
027import org.apache.wicket.model.IModel;
028import org.apache.wicket.util.lang.Args;
029
030
031/**
032 * Model for extracting feedback messages.
033 * 
034 * @author Eelco Hillenius
035 */
036public class FeedbackMessagesModel implements IModel<List<FeedbackMessage>>
037{
038        private static final long serialVersionUID = 1L;
039
040        /** Message filter */
041        private IFeedbackMessageFilter filter;
042
043        /** Lazy loaded, temporary list. */
044        private transient List<FeedbackMessage> messages;
045
046        /** Comparator used for sorting the messages. */
047        private Comparator<FeedbackMessage> sortingComparator;
048
049        private final Component pageResolvingComponent;
050
051        /** 
052         * Controls whether or not feedback from the {@link Session} will be collected.
053         * By default is true.
054         */
055        private boolean includeSession = true;
056
057        /**
058         * Constructor. Creates a model for all feedback messages on the page.
059         * 
060         * @param pageResolvingComponent
061         *            The component where the page will be get from for which messages will be displayed
062         *            usually the same page as the one feedbackpanel is attached to
063         */
064        public FeedbackMessagesModel(Component pageResolvingComponent)
065        {
066                Args.notNull(pageResolvingComponent, "pageResolvingComponent");
067                this.pageResolvingComponent = pageResolvingComponent;
068        }
069
070        /**
071         * Constructor. Creates a model for all feedback messages accepted by the given filter.
072         * 
073         * @param filter
074         *            The filter to apply
075         * @param page
076         *            Page for which messages will be displayed - usually the same page as the one
077         *            feedbackpanel is attached to
078         * 
079         */
080        public FeedbackMessagesModel(Page page, IFeedbackMessageFilter filter)
081        {
082                this(page);
083                setFilter(filter);
084        }
085
086        /**
087         * @return The current message filter
088         */
089        public final IFeedbackMessageFilter getFilter()
090        {
091                return filter;
092        }
093
094        /**
095         * @return The current sorting comparator
096         */
097        public final Comparator<FeedbackMessage> getSortingComparator()
098        {
099                return sortingComparator;
100        }
101
102        @Override
103        public final List<FeedbackMessage> getObject()
104        {
105                if (messages == null)
106                {
107                        // Get filtered messages from page where component lives
108                        messages = collectMessages(pageResolvingComponent, filter);
109
110                        // Sort the list before returning it
111                        if (sortingComparator != null)
112                        {
113                                Collections.sort(messages, sortingComparator);
114                        }
115
116                        // Let subclass do any extra processing it wants to on the messages.
117                        // It may want to do something special, such as removing a given
118                        // message under some special condition or perhaps eliminate
119                        // duplicate messages. It could even add a message under certain
120                        // conditions.
121                        messages = processMessages(messages);
122                }
123                return messages;
124        }
125
126        /**
127         * Collects feedback messages
128         * 
129         * @param pageResolvingComponent
130         * @param filter
131         * @return list of feedback messages
132         */
133        protected List<FeedbackMessage> collectMessages(Component pageResolvingComponent,
134                IFeedbackMessageFilter filter)
135        {
136                return new FeedbackCollector(pageResolvingComponent.getPage(), includeSession).collect(filter);
137        }
138
139        /**
140         * @param filter
141         *            Filter to apply to model
142         * @return this
143         */
144        public final FeedbackMessagesModel setFilter(IFeedbackMessageFilter filter)
145        {
146                this.filter = filter;
147                return this;
148        }
149
150        /**
151         * Sets the comparator used for sorting the messages.
152         * 
153         * @param sortingComparator
154         *            comparator used for sorting the messages
155         * @return this
156         */
157        public final FeedbackMessagesModel setSortingComparator(
158                Comparator<FeedbackMessage> sortingComparator)
159        {
160                if (!(sortingComparator instanceof Serializable))
161                {
162                        throw new IllegalArgumentException("sortingComparator must be serializable");
163                }
164                this.sortingComparator = sortingComparator;
165                return this;
166        }
167
168        /**
169         * Override this method to post process to the FeedbackMessage list.
170         * 
171         * @param messages
172         *            List of sorted and filtered FeedbackMessages for further processing
173         * @return The processed FeedbackMessage list
174         */
175        protected List<FeedbackMessage> processMessages(final List<FeedbackMessage> messages)
176        {
177                return messages;
178        }
179
180        @Override
181        public void setObject(List<FeedbackMessage> object)
182        {
183        }
184
185        @Override
186        public void detach()
187        {
188                messages = null;
189        }
190
191        /**
192         * Controls whether or not feedback from the {@link Session} will be collected.
193         * 
194         * See {@link FeedbackCollector#setIncludeSession} and {@link Session#getFeedbackMessages} 
195         * 
196         * @param includeSession
197         * @return {@code this} for chaining
198         */
199        public FeedbackMessagesModel setIncludeSession(boolean includeSession)
200        {
201                this.includeSession = includeSession;
202                return this;
203        }
204}