1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package gov.nasa.pds.tools.label.validate;
17
18 import java.util.Collection;
19 import java.util.Iterator;
20 import java.util.logging.Level;
21 import java.util.logging.Logger;
22
23 import gov.nasa.pds.tools.dict.Dictionary;
24 import gov.nasa.pds.tools.dict.ElementDefinition;
25 import gov.nasa.pds.tools.label.AttributeStatement;
26 import gov.nasa.pds.tools.label.Numeric;
27 import gov.nasa.pds.tools.label.Sequence;
28 import gov.nasa.pds.tools.label.Set;
29 import gov.nasa.pds.tools.label.Value;
30 import gov.nasa.pds.tools.logging.ToolsLogRecord;
31 import gov.nasa.pds.tools.util.Utility;
32 import gov.nasa.pds.tools.dict.type.InvalidLengthException;
33 import gov.nasa.pds.tools.dict.type.NumericTypeChecker;
34 import gov.nasa.pds.tools.dict.type.OutOfRangeException;
35 import gov.nasa.pds.tools.dict.type.TypeChecker;
36 import gov.nasa.pds.tools.dict.type.TypeCheckerFactory;
37 import gov.nasa.pds.tools.dict.type.UnsupportedTypeException;
38 import gov.nasa.pds.tools.dict.type.InvalidTypeException;
39 import gov.nasa.pds.tools.dict.DictionaryTokens;
40
41 /***
42 * This class will validate an element value or set of values against
43 * an ElementDefinition.
44 * @author pramirez
45 * @version $Revision: 2631 $
46 *
47 */
48 public class ElementValidator implements DictionaryTokens {
49 private static Logger log = Logger.getLogger(ElementValidator.class.getName());
50
51 public static boolean isValid(ElementDefinition definition, AttributeStatement attribute)
52 throws UnsupportedTypeException {
53 boolean valid = true;
54 Value value = attribute.getValue();
55
56
57 if (attribute.hasNamespace()) {
58 if (attribute.getNamespace().length() > NAMESPACE_LENGTH) {
59 valid = false;
60 log.log(new ToolsLogRecord(Level.SEVERE, "Namespace exceeds max length of " +
61 ELEMENT_IDENT_LENGTH + " characters.", attribute.getFilename(), attribute.getContext(), attribute.getLineNumber()));
62 }
63 }
64
65
66 if (attribute.getElementIdentifier().length() > ELEMENT_IDENT_LENGTH) {
67 valid = false;
68 log.log(new ToolsLogRecord(Level.SEVERE, "Identifier exceeds max length of " +
69 ELEMENT_IDENT_LENGTH + " characters.", attribute.getFilename(), attribute.getContext(), attribute.getLineNumber()));
70 }
71
72
73 TypeChecker checker = TypeCheckerFactory.getInstance().newInstance(definition.getDataType());
74
75 boolean valueValid = validate(definition, attribute, checker, value);
76
77 if (!valueValid)
78 valid = false;
79
80 return valid;
81 }
82
83 private static boolean validate(ElementDefinition definition, AttributeStatement attribute, TypeChecker checker, Value value)
84 throws UnsupportedTypeException {
85 boolean valid = true;
86 if (value == null) {
87 log.log(new ToolsLogRecord(Level.WARNING, "Found no value for " + attribute.getIdentifier(),
88 attribute.getFilename(), attribute.getContext(), attribute.getLineNumber()));
89 } else if (value instanceof Set || value instanceof Sequence) {
90 boolean validValues = true;
91 for (Iterator i = ((Collection) value).iterator(); i.hasNext();) {
92 Value v = (Value) i.next();
93 validValues = validate(definition, attribute, checker, v);
94
95 if (!validValues)
96 valid = false;
97 }
98 } else {
99 if (!skipValue(value.toString())) {
100
101 if (definition.hasValidValues()) {
102 if (!definition.getValues().contains(value.toString())) {
103 boolean foundValue = false;
104 boolean manipulated = false;
105
106
107 String filteredValue = Utility.stripNewLines(value.toString());
108
109 if (definition.getValues().contains(filteredValue)) {
110 foundValue = true;
111 } else if (definition.getValues().contains(filteredValue.toUpperCase())) {
112
113 manipulated = true;
114 foundValue = true;
115 } else {
116
117 filteredValue = Utility.filterString(filteredValue.toUpperCase());
118 manipulated = true;
119 if (definition.getValues().contains(filteredValue))
120 foundValue = true;
121 }
122
123 if (!foundValue) {
124
125 if (!VALUE_TYPE_STATIC.equals(definition.getValueType())) {
126 log.log(new ToolsLogRecord(Level.WARNING, value.toString() +
127 " is not in the suggested list of valid values for " + attribute.getIdentifier(),
128 attribute.getFilename(), attribute.getContext(), attribute.getLineNumber()));
129 } else {
130 valid = false;
131 log.log(new ToolsLogRecord(Level.SEVERE, value.toString() +
132 " is not in the list of valid values for " + attribute.getIdentifier(),
133 attribute.getFilename(), attribute.getContext(), attribute.getLineNumber()));
134 }
135 } else if (manipulated) {
136
137 log.log(new ToolsLogRecord(Level.INFO, "Element value was manipulated for " + attribute.getIdentifier() +
138 " in order to match value list.", attribute.getFilename(), attribute.getContext(), attribute.getLineNumber()));
139 }
140 }
141 }
142
143 Object castedValue = null;
144
145 try {
146 castedValue = checker.cast(value.toString());
147 } catch (InvalidTypeException ite) {
148 valid = false;
149 log.log(new ToolsLogRecord(Level.SEVERE, ite.getMessage(), attribute.getFilename(), attribute.getContext(), attribute.getLineNumber()));
150 }
151
152
153 try {
154 checker.checkMinLength(value.toString(), definition.getMinLength());
155 } catch (InvalidLengthException ile) {
156 valid = false;
157 log.log(new ToolsLogRecord(Level.SEVERE, ile.getMessage(), attribute.getFilename(), attribute.getContext(), attribute.getLineNumber()));
158 }
159
160
161 try {
162 checker.checkMaxLength(value.toString(), definition.getMaxLength());
163 } catch (InvalidLengthException ile) {
164 valid = false;
165 log.log(new ToolsLogRecord(Level.SEVERE, ile.getMessage(), attribute.getFilename(), attribute.getContext(), attribute.getLineNumber()));
166 }
167
168
169 if (checker instanceof NumericTypeChecker && castedValue instanceof Number && castedValue != null) {
170 NumericTypeChecker numericChecker = (NumericTypeChecker) checker;
171
172
173 if (definition.hasMinimum()) {
174 try {
175 numericChecker.checkMinValue((Number) castedValue, definition.getMinimum());
176 } catch (OutOfRangeException oor) {
177 valid = false;
178 log.log(new ToolsLogRecord(Level.SEVERE, oor.getMessage(), attribute.getFilename(), attribute.getContext(), attribute.getLineNumber()));
179 }
180 }
181
182
183 if (definition.hasMaximum()) {
184 try {
185 numericChecker.checkMaxValue((Number) castedValue, definition.getMaximum());
186 } catch (OutOfRangeException oor) {
187 valid = false;
188 log.log(new ToolsLogRecord(Level.SEVERE, oor.getMessage(), attribute.getFilename(), attribute.getContext(), attribute.getLineNumber()));
189 }
190 }
191
192
193
194 if (value instanceof Numeric) {
195 Numeric number = (Numeric) value;
196 if (number.getUnits() != null && !definition.isUnitAllowed(number.getUnits())) {
197 boolean unitsValid = false;
198 if (number.getUnits().endsWith("s") &&
199 definition.isUnitAllowed(number.getUnits().substring(0, number.getUnits().length() - 1))) {
200 unitsValid = true;
201 }
202 if (!unitsValid) {
203 valid = false;
204 log.log(new ToolsLogRecord(Level.SEVERE, "Units (" + number.getUnits() + ") do not match " +
205 "those found in the dictionary.", attribute.getFilename(), attribute.getContext(),
206 attribute.getLineNumber()));
207 }
208 }
209 }
210 }
211 }
212 }
213
214 return valid;
215 }
216
217 private static boolean skipValue(String value) {
218 if ("N/A".equals(value) || "NULL".equals(value) || "UNK".equals(value))
219 return true;
220 return false;
221 }
222
223 /***
224 * Checks to see whether an {@link AttributeStatement} is correct. Will look up the definition in
225 * the given dictionary. An object context may be supplied as elements can have aliases that are
226 * appropriate within an object. Set objectContext to null if there if the lookup should be performed
227 * without care to the surrounding object.
228 * @param dictionary where to look up the element
229 * @param objectContext enclosing the element to be looked up
230 * @param attribute statement to be validated
231 * @return flag indicting whether or not the statement was valid against the definition found
232 * @throws DefinitionNotFoundException if definition for element is not found
233 * @throws UnsupportedTypeException if type of element is not supported
234 */
235 public static boolean isValid(Dictionary dictionary, String objectContext, AttributeStatement attribute)
236 throws DefinitionNotFoundException, UnsupportedTypeException {
237 ElementDefinition definition = dictionary.getElementDefinition(objectContext, attribute.getIdentifier());
238
239 if (definition == null)
240 throw new DefinitionNotFoundException("Undefined Element: " + attribute.getIdentifier());
241
242 return isValid(definition, attribute);
243 }
244
245 public static boolean isValid(Dictionary dictionary, AttributeStatement attribute)
246 throws DefinitionNotFoundException, UnsupportedTypeException {
247 return isValid(dictionary, null, attribute);
248 }
249
250 }