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 }