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 }