    001    // Copyright 2006, 2008, 2010, 2011 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 implementation of {@link ValidationTracker}. Works pretty hard to ensure a minimum
    026     * amount of data is stored
    027     * in the HttpSession.
    028     */
    029    public final class ValidationTrackerImpl extends BaseOptimizedSessionPersistedObject implements ValidationTracker, Serializable
    030    {
    031        private static final long serialVersionUID = -8029192726659275677L;
    032
    033        private static class FieldTracker implements Serializable
    034        {
    035            private static final long serialVersionUID = -3653306147088451811L;
    036
    037            private final String fieldName;
    038
    039            private String input;
    040
    041            private String errorMessage;
    042
    043            FieldTracker(String fieldName)
    044            {
    045                this.fieldName = fieldName;
    046            }
    047        }
    048
    049        private List<String> extraErrors;
    050
    051        private List<FieldTracker> fieldTrackers;
    052
    053        // Rebuilt on-demand
    054
    055        private transient Map<String, FieldTracker> fieldToTracker;
    056
    057        private void refreshFieldToTracker()
    058        {
    059            if (fieldToTracker != null)
    060                return;
    061
    062            if (fieldTrackers == null)
    063                return;
    064
    065            fieldToTracker = CollectionFactory.newMap();
    066
    067            for (FieldTracker ft : fieldTrackers)
    068                fieldToTracker.put(ft.fieldName, ft);
    069        }
    070
    071        private FieldTracker get(Field field)
    072        {
    073            String key = field.getControlName();
    074
    075            refreshFieldToTracker();
    076
    077            FieldTracker result = InternalUtils.get(fieldToTracker, key);
    078
    079            if (result == null)
    080                result = new FieldTracker(key);
    081
    082            return result;
    083        }
    084
    085        private void store(FieldTracker fieldTracker)
    086        {
    087            if (fieldTrackers == null)
    088                fieldTrackers = CollectionFactory.newList();
    089
    090            refreshFieldToTracker();
    091
    092            String key = fieldTracker.fieldName;
    093
    094            if (!fieldToTracker.containsKey(key))
    095            {
    096                fieldTrackers.add(fieldTracker);
    097                fieldToTracker.put(key, fieldTracker);
    098            }
    099
    100            markDirty();
    101        }
    102
    103        public void clear()
    104        {
    105            extraErrors = null;
    106            fieldTrackers = null;
    107            fieldToTracker = null;
    108
    109            markDirty();
    110        }
    111
    112        public String getError(Field field)
    113        {
    114            return get(field).errorMessage;
    115        }
    116
    117        public List<String> getErrors()
    118        {
    119            List<String> result = CollectionFactory.newList();
    120
    121            if (extraErrors != null)
    122                result.addAll(extraErrors);
    123
    124            if (fieldTrackers != null)
    125            {
    126                for (FieldTracker ft : fieldTrackers)
    127                {
    128                    String errorMessage = ft.errorMessage;
    129
    130                    if (errorMessage != null)
    131                        result.add(errorMessage);
    132                }
    133            }
    134
    135            return result;
    136        }
    137
    138        public boolean getHasErrors()
    139        {
    140            return !getErrors().isEmpty();
    141        }
    142
    143        public String getInput(Field field)
    144        {
    145            return get(field).input;
    146        }
    147
    148        public boolean inError(Field field)
    149        {
    150            return InternalUtils.isNonBlank(get(field).errorMessage);
    151        }
    152
    153        public void recordError(Field field, String errorMessage)
    154        {
    155            FieldTracker ft = get(field);
    156
    157            ft.errorMessage = errorMessage;
    158
    159            store(ft);
    160        }
    161
    162        public void recordError(String errorMessage)
    163        {
    164            if (extraErrors == null)
    165                extraErrors = CollectionFactory.newList();
    166
    167            extraErrors.add(errorMessage);
    168
    169            markDirty();
    170        }
    171
    172        public void recordInput(Field field, String input)
    173        {
    174            FieldTracker ft = get(field);
    175
    176            ft.input = input;
    177
    178            store(ft);
    179        }
    180    }