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
015package org.apache.tapestry5;
016
017import org.apache.tapestry5.ioc.internal.util.CollectionFactory;
018import org.apache.tapestry5.ioc.internal.util.InternalUtils;
019
020import java.io.Serializable;
021import java.util.List;
022import 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 */
029public 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}