-
Notifications
You must be signed in to change notification settings - Fork 4.9k
/
ValidatorEndpoint.java
260 lines (221 loc) · 10.4 KB
/
ValidatorEndpoint.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
/**
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.camel.component.validator;
import javax.xml.XMLConstants;
import javax.xml.validation.SchemaFactory;
import org.w3c.dom.ls.LSResourceResolver;
import org.apache.camel.Component;
import org.apache.camel.Consumer;
import org.apache.camel.Processor;
import org.apache.camel.Producer;
import org.apache.camel.api.management.ManagedOperation;
import org.apache.camel.api.management.ManagedResource;
import org.apache.camel.processor.validation.DefaultValidationErrorHandler;
import org.apache.camel.processor.validation.SchemaReader;
import org.apache.camel.processor.validation.ValidatingProcessor;
import org.apache.camel.processor.validation.ValidatorErrorHandler;
import org.apache.camel.spi.Metadata;
import org.apache.camel.spi.UriEndpoint;
import org.apache.camel.spi.UriParam;
import org.apache.camel.spi.UriPath;
import org.apache.camel.support.DefaultEndpoint;
/**
* Validates the payload of a message using XML Schema and JAXP Validation.
*/
@ManagedResource(description = "Managed ValidatorEndpoint")
@UriEndpoint(firstVersion = "1.1.0", scheme = "validator", title = "Validator", syntax = "validator:resourceUri", producerOnly = true, label = "core,validation")
public class ValidatorEndpoint extends DefaultEndpoint {
@UriPath(description = "URL to a local resource on the classpath, or a reference to lookup a bean in the Registry,"
+ " or a full URL to a remote resource or resource on the file system which contains the XSD to validate against.")
@Metadata(required = true)
private String resourceUri;
@UriParam(defaultValue = XMLConstants.W3C_XML_SCHEMA_NS_URI, label = "advanced",
description = "Configures the W3C XML Schema Namespace URI.")
private String schemaLanguage = XMLConstants.W3C_XML_SCHEMA_NS_URI;
@UriParam(label = "advanced", description = "To use a custom javax.xml.validation.SchemaFactory")
private SchemaFactory schemaFactory;
@UriParam(label = "advanced", description = "To use a custom org.apache.camel.processor.validation.ValidatorErrorHandler. The default error handler captures the errors and throws an exception.")
private ValidatorErrorHandler errorHandler = new DefaultValidationErrorHandler();
@UriParam(defaultValue = "true", label = "advanced",
description = "Whether the Schema instance should be shared or not. This option is introduced to work around a JDK 1.6.x bug. Xerces should not have this issue.")
private boolean useSharedSchema = true;
@UriParam(label = "advanced", description = "To use a custom LSResourceResolver. Do not use together with resourceResolverFactory")
private LSResourceResolver resourceResolver;
@UriParam(label = "advanced", description = "To use a custom LSResourceResolver which depends on a dynamic endpoint resource URI. " + //
"The default resource resolver factory resturns a resource resolver which can read files from the class path and file system. Do not use together with resourceResolver.")
private ValidatorResourceResolverFactory resourceResolverFactory;
@UriParam(defaultValue = "true", description = "Whether to fail if no body exists.")
private boolean failOnNullBody = true;
@UriParam(defaultValue = "true", description = "Whether to fail if no header exists when validating against a header.")
private boolean failOnNullHeader = true;
@UriParam(description = "To validate against a header instead of the message body.")
private String headerName;
/**
* We need a one-to-one relation between endpoint and schema reader in order
* to be able to clear the cached schema in the schema reader. See method
* {@link #clearCachedSchema}.
*/
private final SchemaReader schemaReader;
private volatile boolean schemaReaderConfigured;
public ValidatorEndpoint() {
schemaReader = new SchemaReader();
}
public ValidatorEndpoint(String endpointUri, Component component, String resourceUri) {
super(endpointUri, component);
this.resourceUri = resourceUri;
schemaReader = new SchemaReader(getCamelContext(), resourceUri);
}
@ManagedOperation(description = "Clears the cached schema, forcing to re-load the schema on next request")
public void clearCachedSchema() {
schemaReader.setSchema(null); // will cause to reload the schema
}
@Override
public Producer createProducer() throws Exception {
if (!schemaReaderConfigured) {
if (resourceResolver != null) {
schemaReader.setResourceResolver(resourceResolver);
} else if (resourceResolverFactory != null) {
resourceResolver = resourceResolverFactory.createResourceResolver(getCamelContext(), resourceUri);
// set the created resource resolver to the resourceResolver variable, so that it can
// be accessed by the endpoint
schemaReader.setResourceResolver(resourceResolver);
} else {
schemaReader.setResourceResolver(new DefaultValidatorResourceResolverFactory().createResourceResolver(getCamelContext(), resourceUri));
}
schemaReader.setSchemaLanguage(getSchemaLanguage());
schemaReader.setSchemaFactory(getSchemaFactory());
// force loading of schema at create time otherwise concurrent
// processing could cause thread safe issues for the
// javax.xml.validation.SchemaFactory
schemaReader.loadSchema();
// configure only once
schemaReaderConfigured = true;
}
ValidatingProcessor validator = new ValidatingProcessor(schemaReader);
configureValidator(validator);
return new ValidatorProducer(this, validator);
}
@Override
public Consumer createConsumer(Processor processor) throws Exception {
throw new UnsupportedOperationException("Cannot consume from validator");
}
@Override
public boolean isSingleton() {
return true;
}
protected void configureValidator(ValidatingProcessor validator) throws Exception {
validator.setErrorHandler(getErrorHandler());
validator.setUseSharedSchema(isUseSharedSchema());
validator.setFailOnNullBody(isFailOnNullBody());
validator.setFailOnNullHeader(isFailOnNullHeader());
validator.setHeaderName(getHeaderName());
}
public String getResourceUri() {
return resourceUri;
}
/**
* URL to a local resource on the classpath,or a reference to lookup a bean in the Registry,
* or a full URL to a remote resource or resource on the file system which contains the XSD to validate against.
*/
public void setResourceUri(String resourceUri) {
this.resourceUri = resourceUri;
}
public String getSchemaLanguage() {
return schemaLanguage;
}
/**
* Configures the W3C XML Schema Namespace URI.
*/
public void setSchemaLanguage(String schemaLanguage) {
this.schemaLanguage = schemaLanguage;
}
public SchemaFactory getSchemaFactory() {
return schemaFactory;
}
/**
* To use a custom javax.xml.validation.SchemaFactory
*/
public void setSchemaFactory(SchemaFactory schemaFactory) {
this.schemaFactory = schemaFactory;
}
public ValidatorErrorHandler getErrorHandler() {
return errorHandler;
}
/**
* To use a custom org.apache.camel.processor.validation.ValidatorErrorHandler.
* <p/>
* The default error handler captures the errors and throws an exception.
*/
public void setErrorHandler(ValidatorErrorHandler errorHandler) {
this.errorHandler = errorHandler;
}
public boolean isUseSharedSchema() {
return useSharedSchema;
}
/**
* Whether the Schema instance should be shared or not. This option is introduced to work around a JDK 1.6.x bug. Xerces should not have this issue.
*/
public void setUseSharedSchema(boolean useSharedSchema) {
this.useSharedSchema = useSharedSchema;
}
public LSResourceResolver getResourceResolver() {
return resourceResolver;
}
/**
* To use a custom LSResourceResolver. See also {@link #setResourceResolverFactory(ValidatorResourceResolverFactory)}
*/
public void setResourceResolver(LSResourceResolver resourceResolver) {
this.resourceResolver = resourceResolver;
}
public ValidatorResourceResolverFactory getResourceResolverFactory() {
return resourceResolverFactory;
}
/** For creating a resource resolver which depends on the endpoint resource URI.
* Must not be used in combination with method {@link #setResourceResolver(LSResourceResolver)}.
* If not set then {@link DefaultValidatorResourceResolverFactory} is used
*/
public void setResourceResolverFactory(ValidatorResourceResolverFactory resourceResolverFactory) {
this.resourceResolverFactory = resourceResolverFactory;
}
public boolean isFailOnNullBody() {
return failOnNullBody;
}
/**
* Whether to fail if no body exists.
*/
public void setFailOnNullBody(boolean failOnNullBody) {
this.failOnNullBody = failOnNullBody;
}
public boolean isFailOnNullHeader() {
return failOnNullHeader;
}
/**
* Whether to fail if no header exists when validating against a header.
*/
public void setFailOnNullHeader(boolean failOnNullHeader) {
this.failOnNullHeader = failOnNullHeader;
}
public String getHeaderName() {
return headerName;
}
/**
* To validate against a header instead of the message body.
*/
public void setHeaderName(String headerName) {
this.headerName = headerName;
}
}