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: 2930 $
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 return isValid(definition, attribute, new DefaultValidationListener());
54 }
55
56 public static boolean isValid(ElementDefinition definition, AttributeStatement attribute, ValidationListener listener)
57 throws UnsupportedTypeException {
58 boolean valid = true;
59 Value value = attribute.getValue();
60
61
62 if (attribute.hasNamespace()) {
63 if (attribute.getNamespace().length() > NAMESPACE_LENGTH) {
64 valid = false;
65 listener.reportError("Namespace exceeds max length of " +
66 ELEMENT_IDENT_LENGTH + " characters.");
67 log.log(new ToolsLogRecord(Level.SEVERE, "Namespace exceeds max length of " +
68 ELEMENT_IDENT_LENGTH + " characters.", attribute.getFilename(), attribute.getContext(), attribute.getLineNumber()));
69 }
70 }
71
72
73 if (attribute.getElementIdentifier().length() > ELEMENT_IDENT_LENGTH) {
74 valid = false;
75 listener.reportError("Identifier exceeds max length of " +
76 ELEMENT_IDENT_LENGTH + " characters.");
77 log.log(new ToolsLogRecord(Level.SEVERE, "Identifier exceeds max length of " +
78 ELEMENT_IDENT_LENGTH + " characters.", attribute.getFilename(), attribute.getContext(), attribute.getLineNumber()));
79 }
80
81
82 TypeChecker checker = TypeCheckerFactory.getInstance().newInstance(definition.getDataType());
83
84 boolean valueValid = validate(definition, attribute, checker, value, listener);
85
86 if (!valueValid)
87 valid = false;
88
89 return valid;
90 }
91
92 private static boolean validate(ElementDefinition definition, AttributeStatement attribute, TypeChecker checker, Value value, ValidationListener listener)
93 throws UnsupportedTypeException {
94 boolean valid = true;
95 if (value == null) {
96 listener.reportWarning("Found no value for " + attribute.getIdentifier());
97 log.log(new ToolsLogRecord(Level.WARNING, "Found no value for " + attribute.getIdentifier(),
98 attribute.getFilename(), attribute.getContext(), attribute.getLineNumber()));
99 } else if (value instanceof Set || value instanceof Sequence) {
100 boolean validValues = true;
101 for (Iterator i = ((Collection) value).iterator(); i.hasNext();) {
102 Value v = (Value) i.next();
103 validValues = validate(definition, attribute, checker, v, listener);
104
105 if (!validValues)
106 valid = false;
107 }
108 } else {
109 if (!skipValue(value.toString())) {
110
111 if (definition.hasValidValues()) {
112 if (!definition.getValues().contains(value.toString())) {
113 boolean foundValue = false;
114 boolean manipulated = false;
115
116
117 String filteredValue = Utility.stripNewLines(value.toString());
118
119 if (definition.getValues().contains(filteredValue)) {
120 foundValue = true;
121 } else if (definition.getValues().contains(filteredValue.toUpperCase())) {
122
123 manipulated = true;
124 foundValue = true;
125 } else {
126
127 filteredValue = Utility.filterString(filteredValue.toUpperCase());
128 manipulated = true;
129 if (definition.getValues().contains(filteredValue))
130 foundValue = true;
131 }
132
133 if (!foundValue) {
134
135 if (!VALUE_TYPE_STATIC.equals(definition.getValueType())) {
136 listener.reportWarning(value.toString() +
137 " is not in the suggested list of valid values for " + attribute.getIdentifier());
138 log.log(new ToolsLogRecord(Level.WARNING, value.toString() +
139 " is not in the suggested list of valid values for " + attribute.getIdentifier(),
140 attribute.getFilename(), attribute.getContext(), attribute.getLineNumber()));
141 } else {
142 valid = false;
143 listener.reportError(value.toString() +
144 " is not in the list of valid values for " + attribute.getIdentifier());
145 log.log(new ToolsLogRecord(Level.SEVERE, value.toString() +
146 " is not in the list of valid values for " + attribute.getIdentifier(),
147 attribute.getFilename(), attribute.getContext(), attribute.getLineNumber()));
148 }
149 } else if (manipulated) {
150
151 log.log(new ToolsLogRecord(Level.INFO, "Element value was manipulated for " + attribute.getIdentifier() +
152 " in order to match value list.", attribute.getFilename(), attribute.getContext(), attribute.getLineNumber()));
153 }
154 }
155 }
156
157 Object castedValue = null;
158
159 try {
160 castedValue = checker.cast(value.toString());
161 } catch (InvalidTypeException ite) {
162 valid = false;
163 listener.reportError(ite.getMessage());
164 log.log(new ToolsLogRecord(Level.SEVERE, ite.getMessage(), attribute.getFilename(), attribute.getContext(), attribute.getLineNumber()));
165 }
166
167
168 try {
169 checker.checkMinLength(value.toString(), definition.getMinLength());
170 } catch (InvalidLengthException ile) {
171 valid = false;
172 listener.reportError(ile.getMessage());
173 log.log(new ToolsLogRecord(Level.SEVERE, ile.getMessage(), attribute.getFilename(), attribute.getContext(), attribute.getLineNumber()));
174 }
175
176
177 try {
178 checker.checkMaxLength(value.toString(), definition.getMaxLength());
179 } catch (InvalidLengthException ile) {
180 valid = false;
181 listener.reportError(ile.getMessage());
182 log.log(new ToolsLogRecord(Level.SEVERE, ile.getMessage(), attribute.getFilename(), attribute.getContext(), attribute.getLineNumber()));
183 }
184
185
186 if (checker instanceof NumericTypeChecker && castedValue instanceof Number && castedValue != null) {
187 NumericTypeChecker numericChecker = (NumericTypeChecker) checker;
188
189
190 if (definition.hasMinimum()) {
191 try {
192 numericChecker.checkMinValue((Number) castedValue, definition.getMinimum());
193 } catch (OutOfRangeException oor) {
194 valid = false;
195 listener.reportError(oor.getMessage());
196 log.log(new ToolsLogRecord(Level.SEVERE, oor.getMessage(), attribute.getFilename(), attribute.getContext(), attribute.getLineNumber()));
197 }
198 }
199
200
201 if (definition.hasMaximum()) {
202 try {
203 numericChecker.checkMaxValue((Number) castedValue, definition.getMaximum());
204 } catch (OutOfRangeException oor) {
205 valid = false;
206 listener.reportError(oor.getMessage());
207 log.log(new ToolsLogRecord(Level.SEVERE, oor.getMessage(), attribute.getFilename(), attribute.getContext(), attribute.getLineNumber()));
208 }
209 }
210
211
212
213 if (value instanceof Numeric) {
214 Numeric number = (Numeric) value;
215 if (number.getUnits() != null && !definition.isUnitAllowed(number.getUnits())) {
216 boolean unitsValid = false;
217 if (number.getUnits().endsWith("s") &&
218 definition.isUnitAllowed(number.getUnits().substring(0, number.getUnits().length() - 1))) {
219 unitsValid = true;
220 }
221 if (!unitsValid) {
222 listener.reportWarning("Units (" + number.getUnits() + ") do not match " +
223 " those found in the dictionary.");
224 log.log(new ToolsLogRecord(Level.WARNING, "Units (" + number.getUnits() + ") do not match " +
225 " those found in the dictionary.", attribute.getFilename(), attribute.getContext(),
226 attribute.getLineNumber()));
227 }
228 }
229 }
230 }
231 }
232 }
233
234 return valid;
235 }
236
237 private static boolean skipValue(String value) {
238 if ("N/A".equals(value) || "NULL".equals(value) || "UNK".equals(value))
239 return true;
240 return false;
241 }
242
243 /***
244 * Checks to see whether an {@link AttributeStatement} is correct. Will look up the definition in
245 * the given dictionary. An object context may be supplied as elements can have aliases that are
246 * appropriate within an object. Set objectContext to null if there if the lookup should be performed
247 * without care to the surrounding object.
248 * @param dictionary where to look up the element
249 * @param objectContext enclosing the element to be looked up
250 * @param attribute statement to be validated
251 * @return flag indicting whether or not the statement was valid against the definition found
252 * @throws DefinitionNotFoundException if definition for element is not found
253 * @throws UnsupportedTypeException if type of element is not supported
254 */
255 public static boolean isValid(Dictionary dictionary, String objectContext, AttributeStatement attribute)
256 throws DefinitionNotFoundException, UnsupportedTypeException {
257 return isValid(dictionary, objectContext, attribute, new DefaultValidationListener());
258 }
259
260
261 public static boolean isValid(Dictionary dictionary, String objectContext, AttributeStatement attribute, ValidationListener listener)
262 throws DefinitionNotFoundException, UnsupportedTypeException {
263 ElementDefinition definition = dictionary.getElementDefinition(objectContext, attribute.getIdentifier());
264
265 if (definition == null)
266 throw new DefinitionNotFoundException("Undefined Element: " + attribute.getIdentifier());
267
268 return isValid(definition, attribute, listener);
269 }
270
271 public static boolean isValid(Dictionary dictionary, AttributeStatement attribute)
272 throws DefinitionNotFoundException, UnsupportedTypeException {
273 return isValid(dictionary, attribute, new DefaultValidationListener());
274 }
275
276 public static boolean isValid(Dictionary dictionary, AttributeStatement attribute, ValidationListener listener)
277 throws DefinitionNotFoundException, UnsupportedTypeException {
278 return isValid(dictionary, null, attribute, listener);
279 }
280
281 }