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.commons.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 return field.getControlName(); 074 } 075 076 private FieldTracker get(Field field) 077 { 078 String key = getKey(field); 079 080 refreshFieldToTracker(); 081 082 FieldTracker result = InternalUtils.get(fieldToTracker, key); 083 084 if (result == null) 085 result = new FieldTracker(key); 086 087 return result; 088 } 089 090 private void store(FieldTracker fieldTracker) 091 { 092 if (fieldTrackers == null) 093 fieldTrackers = CollectionFactory.newList(); 094 095 refreshFieldToTracker(); 096 097 String key = fieldTracker.validationId; 098 099 if (!fieldToTracker.containsKey(key)) 100 { 101 fieldTrackers.add(fieldTracker); 102 fieldToTracker.put(key, fieldTracker); 103 } 104 105 markDirty(); 106 } 107 108 public void clear() 109 { 110 extraErrors = null; 111 fieldTrackers = null; 112 fieldToTracker = null; 113 114 markDirty(); 115 } 116 117 public String getError(Field field) 118 { 119 return get(field).errorMessage; 120 } 121 122 public List<String> getErrors() 123 { 124 List<String> result = CollectionFactory.newList(); 125 126 if (extraErrors != null) 127 result.addAll(extraErrors); 128 129 if (fieldTrackers != null) 130 { 131 for (FieldTracker ft : fieldTrackers) 132 { 133 String errorMessage = ft.errorMessage; 134 135 if (errorMessage != null) 136 result.add(errorMessage); 137 } 138 } 139 140 return result; 141 } 142 143 public List<String> getUnassociatedErrors() 144 { 145 if (extraErrors == null) 146 { 147 return Collections.emptyList(); 148 } 149 150 return Collections.unmodifiableList(extraErrors); 151 } 152 153 public boolean getHasErrors() 154 { 155 return !getErrors().isEmpty(); 156 } 157 158 public String getInput(Field field) 159 { 160 return get(field).input; 161 } 162 163 public boolean inError(Field field) 164 { 165 return InternalUtils.isNonBlank(get(field).errorMessage); 166 } 167 168 public void recordError(Field field, String errorMessage) 169 { 170 FieldTracker ft = get(field); 171 172 ft.errorMessage = errorMessage; 173 174 store(ft); 175 } 176 177 public void recordError(String errorMessage) 178 { 179 if (extraErrors == null) 180 extraErrors = CollectionFactory.newList(); 181 182 extraErrors.add(errorMessage); 183 184 markDirty(); 185 } 186 187 public void recordInput(Field field, String input) 188 { 189 FieldTracker ft = get(field); 190 191 ft.input = input; 192 193 store(ft); 194 } 195}