Repository: camel Updated Branches: refs/heads/master 092f16ebc -> 03b5c2943
CAMEL-9572: Validator: support custom resource resolver factory support for custom resource resolvers which depend on the resource URI of the endpoint and which works also for dynamic endpoints Project: http://git-wip-us.apache.org/repos/asf/camel/repo Commit: http://git-wip-us.apache.org/repos/asf/camel/commit/03b5c294 Tree: http://git-wip-us.apache.org/repos/asf/camel/tree/03b5c294 Diff: http://git-wip-us.apache.org/repos/asf/camel/diff/03b5c294 Branch: refs/heads/master Commit: 03b5c29436a80cf8681ddf514dcaa313e2b105b0 Parents: 092f16e Author: Franz Forsthofer <franz.forstho...@sap.com> Authored: Sat Feb 6 15:58:35 2016 +0100 Committer: Franz Forsthofer <franz.forstho...@sap.com> Committed: Mon Feb 8 14:20:49 2016 +0100 ---------------------------------------------------------------------- ...DefaultValidatorResourceResolverFactory.java | 34 ++++ .../component/validator/ValidatorComponent.java | 23 +++ .../component/validator/ValidatorEndpoint.java | 26 ++- .../ValidatorResourceResolverFactory.java | 50 ++++++ .../ValidatorResourceResolverFactoryTest.java | 164 +++++++++++++++++++ 5 files changed, 294 insertions(+), 3 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/camel/blob/03b5c294/camel-core/src/main/java/org/apache/camel/component/validator/DefaultValidatorResourceResolverFactory.java ---------------------------------------------------------------------- diff --git a/camel-core/src/main/java/org/apache/camel/component/validator/DefaultValidatorResourceResolverFactory.java b/camel-core/src/main/java/org/apache/camel/component/validator/DefaultValidatorResourceResolverFactory.java new file mode 100644 index 0000000..ac06bd1 --- /dev/null +++ b/camel-core/src/main/java/org/apache/camel/component/validator/DefaultValidatorResourceResolverFactory.java @@ -0,0 +1,34 @@ +/** + * 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 org.w3c.dom.ls.LSResourceResolver; + +import org.apache.camel.CamelContext; + +/** + * Default resource rsolver factory which instantiates the default resource + * rsolver ({@link DefaultLSResourceResolver}). + */ +public class DefaultValidatorResourceResolverFactory implements ValidatorResourceResolverFactory { + + @Override + public LSResourceResolver createResourceResolver(CamelContext camelContext, String rootResourceUri) { + return new DefaultLSResourceResolver(camelContext, rootResourceUri); + } + +} http://git-wip-us.apache.org/repos/asf/camel/blob/03b5c294/camel-core/src/main/java/org/apache/camel/component/validator/ValidatorComponent.java ---------------------------------------------------------------------- diff --git a/camel-core/src/main/java/org/apache/camel/component/validator/ValidatorComponent.java b/camel-core/src/main/java/org/apache/camel/component/validator/ValidatorComponent.java index 07e038a..6756530 100644 --- a/camel-core/src/main/java/org/apache/camel/component/validator/ValidatorComponent.java +++ b/camel-core/src/main/java/org/apache/camel/component/validator/ValidatorComponent.java @@ -20,6 +20,7 @@ import java.util.Map; import org.apache.camel.Endpoint; import org.apache.camel.impl.UriEndpointComponent; +import org.apache.camel.spi.Metadata; /** * The <a href="http://camel.apache.org/validation.html">Validator Component</a> is for validating XML against a schema @@ -28,6 +29,9 @@ import org.apache.camel.impl.UriEndpointComponent; */ public class ValidatorComponent extends UriEndpointComponent { + @Metadata(label = "advanced", description = "To use a custom LSResourceResolver which depends on a dynamic endpoint resource URI") + private ValidatorResourceResolverFactory resourceResolverFactory; + public ValidatorComponent() { this(ValidatorEndpoint.class); } @@ -36,8 +40,27 @@ public class ValidatorComponent extends UriEndpointComponent { super(endpointClass); } + public ValidatorResourceResolverFactory getResourceResolverFactory() { + return resourceResolverFactory; + } + + public void setResourceResolverFactory(ValidatorResourceResolverFactory resourceResolverFactory) { + this.resourceResolverFactory = resourceResolverFactory; + } + protected Endpoint createEndpoint(String uri, String remaining, Map<String, Object> parameters) throws Exception { ValidatorEndpoint endpoint = new ValidatorEndpoint(uri, this, remaining); + // lookup custom resolver to use + ValidatorResourceResolverFactory resolverFactory = resolveAndRemoveReferenceParameter(parameters, "resourceResolverFactory", ValidatorResourceResolverFactory.class); + if (resolverFactory == null) { + // not in endpoint then use component specific resource resolver factory + resolverFactory = getResourceResolverFactory(); + } + if (resolverFactory == null) { + // fallback to use a Camel default resource resolver factory + resolverFactory = new DefaultValidatorResourceResolverFactory(); + } + endpoint.setResourceResolverFactory(resolverFactory); setProperties(endpoint, parameters); return endpoint; } http://git-wip-us.apache.org/repos/asf/camel/blob/03b5c294/camel-core/src/main/java/org/apache/camel/component/validator/ValidatorEndpoint.java ---------------------------------------------------------------------- diff --git a/camel-core/src/main/java/org/apache/camel/component/validator/ValidatorEndpoint.java b/camel-core/src/main/java/org/apache/camel/component/validator/ValidatorEndpoint.java index 6b04a8c..8cd175e 100644 --- a/camel-core/src/main/java/org/apache/camel/component/validator/ValidatorEndpoint.java +++ b/camel-core/src/main/java/org/apache/camel/component/validator/ValidatorEndpoint.java @@ -69,8 +69,11 @@ public class ValidatorEndpoint extends DefaultEndpoint { @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") + @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.") @@ -110,8 +113,13 @@ public class ValidatorEndpoint extends DefaultEndpoint { if (!schemaReaderConfigured) { if (resourceResolver != null) { schemaReader.setResourceResolver(resourceResolver); + } else if (resourceResolverFactory != null) { + // set the created resource resolver to the resourceResolver variable, so that it can + // be accessed by the endpoint + resourceResolver = resourceResolverFactory.createResourceResolver(getCamelContext(), resourceUri); + schemaReader.setResourceResolver(resourceResolver); } else { - schemaReader.setResourceResolver(new DefaultLSResourceResolver(getCamelContext(), resourceUri)); + schemaReader.setResourceResolver(new DefaultValidatorResourceResolverFactory().createResourceResolver(getCamelContext(), resourceUri)); } schemaReader.setSchemaLanguage(getSchemaLanguage()); schemaReader.setSchemaFactory(getSchemaFactory()); @@ -241,12 +249,24 @@ public class ValidatorEndpoint extends DefaultEndpoint { } /** - * To use a custom LSResourceResolver + * 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; } http://git-wip-us.apache.org/repos/asf/camel/blob/03b5c294/camel-core/src/main/java/org/apache/camel/component/validator/ValidatorResourceResolverFactory.java ---------------------------------------------------------------------- diff --git a/camel-core/src/main/java/org/apache/camel/component/validator/ValidatorResourceResolverFactory.java b/camel-core/src/main/java/org/apache/camel/component/validator/ValidatorResourceResolverFactory.java new file mode 100644 index 0000000..8004e72 --- /dev/null +++ b/camel-core/src/main/java/org/apache/camel/component/validator/ValidatorResourceResolverFactory.java @@ -0,0 +1,50 @@ +/** + * 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 org.w3c.dom.ls.LSResourceResolver; + +import org.apache.camel.CamelContext; + +/** + * Can be used to create custom resource resolver for the validator endpoint. + * This interface is useful, if the custom resource resolver depends on the + * resource URI specified in the validator endpoint. The resource URI of the + * endpoint can be even dynamic, like in the following example: + * + * <pre> + * {@code <camel:recipientList>} + * {@code <camel:simple>}validator:${header.XSD_FILE}?resourceResolverFactory=#resourceResolverFactory{@code</camel:simple>} + * {@code </camel:recipientList>} + * </pre> + * + * The dynamic resource URI given in ${header.XSD_FILE} will be past as + * rootResourceUri parameter in the method + * {@link #createResourceResolver(CamelContext, String)} + */ +public interface ValidatorResourceResolverFactory { + + /** + * Method is called during the creation of a validator endpoint. + * + * @param camelContext camel context + * @param rootResourceUri resource URI specified in the endpoint URI + * @return resource resolver + */ + LSResourceResolver createResourceResolver(CamelContext camelContext, String rootResourceUri); + +} http://git-wip-us.apache.org/repos/asf/camel/blob/03b5c294/camel-core/src/test/java/org/apache/camel/component/validator/ValidatorResourceResolverFactoryTest.java ---------------------------------------------------------------------- diff --git a/camel-core/src/test/java/org/apache/camel/component/validator/ValidatorResourceResolverFactoryTest.java b/camel-core/src/test/java/org/apache/camel/component/validator/ValidatorResourceResolverFactoryTest.java new file mode 100644 index 0000000..b55aad7 --- /dev/null +++ b/camel-core/src/test/java/org/apache/camel/component/validator/ValidatorResourceResolverFactoryTest.java @@ -0,0 +1,164 @@ +/** + * 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 java.util.HashSet; +import java.util.Set; + +import org.apache.camel.CamelContext; +import org.apache.camel.ContextTestSupport; +import org.apache.camel.builder.RouteBuilder; +import org.apache.camel.component.mock.MockEndpoint; +import org.apache.camel.impl.JndiRegistry; +import org.apache.camel.model.language.ConstantExpression; +import org.apache.camel.model.language.SimpleExpression; +import org.junit.Assert; +import org.w3c.dom.ls.LSInput; +import org.w3c.dom.ls.LSResourceResolver; + +public class ValidatorResourceResolverFactoryTest extends ContextTestSupport { + + private JndiRegistry registry; + + public void testConfigurationOnEndpoint() throws Exception { + // ensure that validator from test method "testConfigurationOnComponent" + // is unbind + registry.getContext().unbind("validator"); + + String directStart = "direct:start"; + String endpointUri = "validator:org/apache/camel/component/validator/xsds/person.xsd?resourceResolverFactory=#resourceResolverFactory"; + + execute(directStart, endpointUri); + } + + public void testConfigurationOnComponent() throws Exception { + // set resource resolver factory on component + ValidatorComponent validatorComponent = new ValidatorComponent(); + validatorComponent.setResourceResolverFactory(new ResourceResolverFactoryImpl()); + registry.bind("validator", validatorComponent); + + String directStart = "direct:startComponent"; + String endpointUri = "validator:org/apache/camel/component/validator/xsds/person.xsd"; + execute(directStart, endpointUri); + + } + + void execute(String directStart, String endpointUri) throws InterruptedException { + MockEndpoint endEndpoint = resolveMandatoryEndpoint("mock:end", MockEndpoint.class); + endEndpoint.expectedMessageCount(1); + + final String body = "<p:person user=\"james\" xmlns:p=\"org.person\" xmlns:h=\"org.health.check.person\" xmlns:c=\"org.health.check.common\">\n" // + + " <p:firstName>James</p:firstName>\n" // + + " <p:lastName>Strachan</p:lastName>\n" // + + " <p:city>London</p:city>\n" // + + " <h:health>\n"// + + " <h:lastCheck>2011-12-23</h:lastCheck>\n" // + + " <h:status>OK</h:status>\n" // + + " <c:commonElement>" // + + " <c:element1/>" // + + " <c:element2/>" // + + " </c:commonElement>" // + + " </h:health>\n" // + + "</p:person>"; + + template.sendBody(directStart, body); + + // fetch dynamic endpoint + ValidatorEndpoint validatorEndpoint = null; + for (int i = 0; i < 5; i++) { + validatorEndpoint = resolveMandatoryEndpoint(endpointUri, ValidatorEndpoint.class); + if (validatorEndpoint != null) { + break; + } + // wait until endpoint is resolved + Thread.sleep(50); + } + MockEndpoint.assertIsSatisfied(endEndpoint); + Assert.assertNotNull(validatorEndpoint); + CustomResourceResolver resolver = (CustomResourceResolver)validatorEndpoint.getResourceResolver(); + + Set<String> uris = resolver.getResolvedResourceUris(); + checkResourceUri(uris, "../type2.xsd"); + checkResourceUri(uris, "health/health.xsd"); + checkResourceUri(uris, "type1.xsd"); + checkResourceUri(uris, "common/common.xsd"); + } + + void checkResourceUri(Set<String> uris, String resourceUri) { + Assert.assertTrue("Missing resource uri " + resourceUri + " in resolved resource URI set", uris.contains(resourceUri)); + } + + @Override + protected JndiRegistry createRegistry() throws Exception { + registry = super.createRegistry(); + registry.bind("resourceResolverFactory", new ResourceResolverFactoryImpl()); + return registry; + + } + + @Override + protected RouteBuilder[] createRouteBuilders() throws Exception { + return new RouteBuilder[] {new RouteBuilder() { + @Override + public void configure() throws Exception { + from("direct:start").setHeader("xsd_file", new ConstantExpression("org/apache/camel/component/validator/xsds/person.xsd")) + .recipientList(new SimpleExpression("validator:${header.xsd_file}?resourceResolverFactory=#resourceResolverFactory")).to("mock:end"); + } + + }, new RouteBuilder() { + @Override + public void configure() throws Exception { + + from("direct:startComponent").setHeader("xsd_file", new ConstantExpression("org/apache/camel/component/validator/xsds/person.xsd")) + .recipientList(new SimpleExpression("validator:${header.xsd_file}")).to("mock:end"); + + } + }}; + } + + static class ResourceResolverFactoryImpl implements ValidatorResourceResolverFactory { + + @Override + public LSResourceResolver createResourceResolver(CamelContext camelContext, String rootResourceUri) { + return new CustomResourceResolver(camelContext, rootResourceUri); + } + + } + + /** Custom resource resolver which collects all resolved resource URIs. */ + static class CustomResourceResolver extends DefaultLSResourceResolver { + + private final Set<String> resolvedRsourceUris = new HashSet<>(); + + CustomResourceResolver(CamelContext camelContext, String resourceUri) { + super(camelContext, resourceUri); + } + + public Set<String> getResolvedResourceUris() { + return resolvedRsourceUris; + } + + @Override + public LSInput resolveResource(String type, String namespaceURI, String publicId, String systemId, String baseURI) { + LSInput result = super.resolveResource(type, namespaceURI, publicId, systemId, baseURI); + resolvedRsourceUris.add(systemId); + return result; + } + + } + +}