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 }