001    // Copyright 2006, 2008 The Apache Software Foundation
002    //
003    // Licensed under the Apache License, Version 2.0 (the "License");
004    // you may not use this file except in compliance with the License.
005    // You may obtain a copy of the License at
006    //
007    //     http://www.apache.org/licenses/LICENSE-2.0
008    //
009    // Unless required by applicable law or agreed to in writing, software
010    // distributed under the License is distributed on an "AS IS" BASIS,
011    // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
012    // See the License for the specific language governing permissions and
013    // limitations under the License.
014    
015    package org.apache.tapestry5;
016    
017    import org.apache.tapestry5.ioc.internal.util.CollectionFactory;
018    import org.apache.tapestry5.ioc.internal.util.InternalUtils;
019    
020    import java.io.Serializable;
021    import java.util.List;
022    import java.util.Map;
023    
024    /**
025     * Standard implmentation of {@link ValidationTracker}. Works pretty hard to ensure a minimum amount of data is stored
026     * in the HttpSession.
027     */
028    public final class ValidationTrackerImpl extends BaseOptimizedSessionPersistedObject implements ValidationTracker, Serializable
029    {
030        private static final long serialVersionUID = -8029192726659275677L;
031    
032        private static class FieldTracker implements Serializable
033        {
034            private static final long serialVersionUID = -3653306147088451811L;
035    
036            private final String fieldName;
037    
038            private String input;
039    
040            private String errorMessage;
041    
042            FieldTracker(String fieldName)
043            {
044                this.fieldName = fieldName;
045            }
046        }
047    
048        private List<String> extraErrors;
049    
050        private List<FieldTracker> fieldTrackers;
051    
052        // Rebuilt on-demand
053    
054        private transient Map<String, FieldTracker> fieldToTracker;
055    
056        private void refreshFieldToTracker()
057        {
058            if (fieldToTracker != null)
059                return;
060    
061            if (fieldTrackers == null)
062                return;
063    
064            fieldToTracker = CollectionFactory.newMap();
065    
066            for (FieldTracker ft : fieldTrackers)
067                fieldToTracker.put(ft.fieldName, ft);
068        }
069    
070        private FieldTracker get(Field field)
071        {
072            String key = field.getControlName();
073    
074            refreshFieldToTracker();
075    
076            FieldTracker result = InternalUtils.get(fieldToTracker, key);
077    
078            if (result == null)
079                result = new FieldTracker(key);
080    
081            return result;
082        }
083    
084        private void store(FieldTracker fieldTracker)
085        {
086            markDirty();
087    
088            if (fieldTrackers == null)
089                fieldTrackers = CollectionFactory.newList();
090    
091            refreshFieldToTracker();
092    
093            String key = fieldTracker.fieldName;
094    
095            if (!fieldToTracker.containsKey(key))
096            {
097                fieldTrackers.add(fieldTracker);
098                fieldToTracker.put(key, fieldTracker);
099            }
100        }
101    
102        public void clear()
103        {
104            markDirty();
105    
106            extraErrors = null;
107            fieldTrackers = null;
108            fieldToTracker = null;
109        }
110    
111        public String getError(Field field)
112        {
113            return get(field).errorMessage;
114        }
115    
116        public List<String> getErrors()
117        {
118            List<String> result = CollectionFactory.newList();
119    
120            if (extraErrors != null)
121                result.addAll(extraErrors);
122    
123            if (fieldTrackers != null)
124            {
125                for (FieldTracker ft : fieldTrackers)
126                {
127                    String errorMessage = ft.errorMessage;
128    
129                    if (errorMessage != null)
130                        result.add(errorMessage);
131                }
132            }
133    
134            return result;
135        }
136    
137        public boolean getHasErrors()
138        {
139            return !getErrors().isEmpty();
140        }
141    
142        public String getInput(Field field)
143        {
144            return get(field).input;
145        }
146    
147        public boolean inError(Field field)
148        {
149            return InternalUtils.isNonBlank(get(field).errorMessage);
150        }
151    
152        public void recordError(Field field, String errorMessage)
153        {
154            FieldTracker ft = get(field);
155    
156            ft.errorMessage = errorMessage;
157    
158            store(ft);
159        }
160    
161        public void recordError(String errorMessage)
162        {
163            markDirty();
164    
165            if (extraErrors == null)
166                extraErrors = CollectionFactory.newList();
167    
168            extraErrors.add(errorMessage);
169        }
170    
171        public void recordInput(Field field, String input)
172        {
173            FieldTracker ft = get(field);
174    
175            ft.input = input;
176    
177            store(ft);
178        }
179    }