001// Licensed under the Apache License, Version 2.0 (the "License"); 002// you may not use this file except in compliance with the License. 003// You may obtain a copy of the License at 004// 005// http://www.apache.org/licenses/LICENSE-2.0 006// 007// Unless required by applicable law or agreed to in writing, software 008// distributed under the License is distributed on an "AS IS" BASIS, 009// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 010// See the License for the specific language governing permissions and 011// limitations under the License. 012 013package org.apache.tapestry5; 014 015import org.apache.tapestry5.ioc.internal.util.CollectionFactory; 016import org.apache.tapestry5.ioc.internal.util.InternalUtils; 017 018import java.io.Serializable; 019import java.util.Collections; 020import java.util.List; 021import java.util.Map; 022 023/** 024 * Standard implementation of {@link ValidationTracker}. Works pretty hard to ensure a minimum 025 * amount of data is stored 026 * in the HttpSession. 027 */ 028public 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 validationId; 037 038 private String input; 039 040 private String errorMessage; 041 042 FieldTracker(String validationId) 043 { 044 this.validationId = validationId; 045 } 046 } 047 048 private List<String> extraErrors; 049 050 private List<FieldTracker> fieldTrackers; 051 052 // Rebuilt on-demand 053 // Keyed on validationId 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.validationId, ft); 069 } 070 071 private String getKey(Field field) 072 { 073 if (field instanceof Field2) 074 { 075 Field2 field2 = (Field2) field; 076 return field2.getValidationId(); 077 } 078 079 return field.getControlName(); 080 } 081 082 private FieldTracker get(Field field) 083 { 084 String key = getKey(field); 085 086 refreshFieldToTracker(); 087 088 FieldTracker result = InternalUtils.get(fieldToTracker, key); 089 090 if (result == null) 091 result = new FieldTracker(key); 092 093 return result; 094 } 095 096 private void store(FieldTracker fieldTracker) 097 { 098 if (fieldTrackers == null) 099 fieldTrackers = CollectionFactory.newList(); 100 101 refreshFieldToTracker(); 102 103 String key = fieldTracker.validationId; 104 105 if (!fieldToTracker.containsKey(key)) 106 { 107 fieldTrackers.add(fieldTracker); 108 fieldToTracker.put(key, fieldTracker); 109 } 110 111 markDirty(); 112 } 113 114 public void clear() 115 { 116 extraErrors = null; 117 fieldTrackers = null; 118 fieldToTracker = null; 119 120 markDirty(); 121 } 122 123 public String getError(Field field) 124 { 125 return get(field).errorMessage; 126 } 127 128 public List<String> getErrors() 129 { 130 List<String> result = CollectionFactory.newList(); 131 132 if (extraErrors != null) 133 result.addAll(extraErrors); 134 135 if (fieldTrackers != null) 136 { 137 for (FieldTracker ft : fieldTrackers) 138 { 139 String errorMessage = ft.errorMessage; 140 141 if (errorMessage != null) 142 result.add(errorMessage); 143 } 144 } 145 146 return result; 147 } 148 149 public List<String> getUnassociatedErrors() 150 { 151 if (extraErrors == null) 152 { 153 return Collections.emptyList(); 154 } 155 156 return Collections.unmodifiableList(extraErrors); 157 } 158 159 public boolean getHasErrors() 160 { 161 return !getErrors().isEmpty(); 162 } 163 164 public String getInput(Field field) 165 { 166 return get(field).input; 167 } 168 169 public boolean inError(Field field) 170 { 171 return InternalUtils.isNonBlank(get(field).errorMessage); 172 } 173 174 public void recordError(Field field, String errorMessage) 175 { 176 FieldTracker ft = get(field); 177 178 ft.errorMessage = errorMessage; 179 180 store(ft); 181 } 182 183 public void recordError(String errorMessage) 184 { 185 if (extraErrors == null) 186 extraErrors = CollectionFactory.newList(); 187 188 extraErrors.add(errorMessage); 189 190 markDirty(); 191 } 192 193 public void recordInput(Field field, String input) 194 { 195 FieldTracker ft = get(field); 196 197 ft.input = input; 198 199 store(ft); 200 } 201}