1 /*
2 * Copyright [2005] [University Corporation for Advanced Internet Development, Inc.]
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 package org.opensaml.xml.validation;
18
19 import java.util.ArrayList;
20 import java.util.Collections;
21 import java.util.List;
22 import java.util.Map;
23 import java.util.concurrent.ConcurrentHashMap;
24
25 import javax.xml.namespace.QName;
26
27 import org.opensaml.xml.XMLObject;
28 import org.slf4j.Logger;
29 import org.slf4j.LoggerFactory;
30
31 /**
32 * A collection of validators that can be applied to an XMLObject and its children. These collections can represent
33 * usage specific checks, such as those outlined in things like profiles for specific XML specification.
34 *
35 * Registered {@link org.opensaml.xml.validation.Validator}s must be stateless. The xmlObjectTarget may be the
36 * XMLObject's element QName retrieved by {@link org.opensaml.xml.XMLObject#getElementQName()} or schema type, retrieved
37 * by {@link org.opensaml.xml.XMLObject#getSchemaType()}, with schema type registered checks performed first.
38 */
39 public class ValidatorSuite {
40
41 /** Class logger. */
42 private final Logger log = LoggerFactory.getLogger(ValidatorSuite.class);
43
44 /** Unique ID for this suite. */
45 private String id;
46
47 /** Validators registered in this suite. */
48 private Map<QName, List<Validator>> validators;
49
50 /**
51 * Constructor.
52 *
53 * @param suiteId unique ID for this suite
54 */
55 public ValidatorSuite(String suiteId) {
56 validators = new ConcurrentHashMap<QName, List<Validator>>();
57 id = suiteId;
58 }
59
60 /**
61 * Gets a unique ID for this suite.
62 *
63 * @return a unique ID for this suite
64 */
65 public String getId() {
66 return id;
67 }
68
69 /**
70 * Evaluates the registered validators against the given XMLObject and it's children.
71 *
72 * @param xmlObject the XMLObject to validate
73 *
74 * @throws ValidationException thrown if the element is not valid
75 */
76 public void validate(XMLObject xmlObject) throws ValidationException {
77 if (xmlObject == null) {
78 return;
79 }
80
81 log.debug("Beginning to verify XMLObject {} and its children", xmlObject.getElementQName());
82 performValidation(xmlObject);
83
84 List<XMLObject> children = xmlObject.getOrderedChildren();
85 if (children != null) {
86 for (XMLObject child : children) {
87 validate(child);
88 }
89 }
90 }
91
92 /**
93 * Gets an immutable list of validators for a given XMLObject target.
94 *
95 * @param xmlObjectTarget the XMLObject the returned list of validators operates on
96 *
97 * @return the list of validators for the XMLObject
98 */
99 public List<Validator> getValidators(QName xmlObjectTarget) {
100 return Collections.unmodifiableList(validators.get(xmlObjectTarget));
101 }
102
103 /**
104 * Registers a new validator in the suite.
105 *
106 * @param validator the validator
107 * @param xmlObjectTarget the XMLObject the validator should operate on
108 */
109 public void registerValidator(QName xmlObjectTarget, Validator validator) {
110 List<Validator> targetValidators = validators.get(xmlObjectTarget);
111
112 if (targetValidators == null) {
113 targetValidators = new ArrayList<Validator>();
114 validators.put(xmlObjectTarget, targetValidators);
115 }
116
117 targetValidators.add(validator);
118 }
119
120 /**
121 * Removes a validator from this suite.
122 *
123 * @param xmlObjectTarget the XMLObject the validator is currently registered for
124 * @param validator the validator to remove
125 */
126 public void deregisterValidator(QName xmlObjectTarget, Validator validator) {
127 List<Validator> targetValidators = validators.get(xmlObjectTarget);
128
129 if (targetValidators != null) {
130 targetValidators.remove(validator);
131 }
132 }
133
134 /**
135 * Validates the given XMLObject. Does NOT validate its children.
136 *
137 * @param xmlObject the XMLObject to validate.
138 *
139 * @throws ValidationException thrown if the XMLObject does not validate
140 */
141 private void performValidation(XMLObject xmlObject) throws ValidationException {
142 QName schemaType = xmlObject.getSchemaType();
143 if (schemaType != null) {
144 log.debug("Validating XMLObject {} against validators registered under its schema type {}", xmlObject
145 .getElementQName(), schemaType);
146 performValidation(schemaType, xmlObject);
147 }
148
149 log.debug("Validating XMLObject {} against validators registered under its element QName", xmlObject
150 .getElementQName());
151 performValidation(xmlObject.getElementQName(), xmlObject);
152 }
153
154 /**
155 * Validates the given XMLObject against the validators registered under the given key.
156 *
157 * @param validatorSetKey the key to the list of validators
158 * @param xmlObject the XMLObject to validate
159 *
160 * @throws ValidationException thrown if any validations fail
161 */
162 private void performValidation(QName validatorSetKey, XMLObject xmlObject) throws ValidationException {
163 List<Validator> elementQNameValidators = validators.get(validatorSetKey);
164 if (elementQNameValidators != null) {
165 for (Validator validator : elementQNameValidators) {
166 log.debug("Validating XMLObject {} against Validator {}", xmlObject.getElementQName(), validator
167 .getClass().getName());
168 validator.validate(xmlObject);
169 }
170 } else {
171 log.debug("No validators registered for XMLObject {} under QName {}", xmlObject.getElementQName(),
172 validatorSetKey);
173 }
174 }
175 }