Author: ningjiang Date: Fri Dec 21 02:18:34 2012 New Revision: 1424788 URL: http://svn.apache.org/viewvc?rev=1424788&view=rev Log: CAMEL-5837 fix the schema validator imports with relative path issue
Added: camel/trunk/camel-core/src/test/java/org/apache/camel/component/validator/ValidatorIncludeRelativeRouteTest.java camel/trunk/camel-core/src/test/resources/org/apache/camel/component/validator/xsds/ camel/trunk/camel-core/src/test/resources/org/apache/camel/component/validator/xsds/health/ camel/trunk/camel-core/src/test/resources/org/apache/camel/component/validator/xsds/health/common/ camel/trunk/camel-core/src/test/resources/org/apache/camel/component/validator/xsds/health/common/common.xsd camel/trunk/camel-core/src/test/resources/org/apache/camel/component/validator/xsds/health/health.xsd camel/trunk/camel-core/src/test/resources/org/apache/camel/component/validator/xsds/person.xsd Modified: camel/trunk/camel-core/src/main/java/org/apache/camel/component/validator/DefaultLSResourceResolver.java camel/trunk/camel-core/src/main/java/org/apache/camel/util/FileUtil.java Modified: camel/trunk/camel-core/src/main/java/org/apache/camel/component/validator/DefaultLSResourceResolver.java URL: http://svn.apache.org/viewvc/camel/trunk/camel-core/src/main/java/org/apache/camel/component/validator/DefaultLSResourceResolver.java?rev=1424788&r1=1424787&r2=1424788&view=diff ============================================================================== --- camel/trunk/camel-core/src/main/java/org/apache/camel/component/validator/DefaultLSResourceResolver.java (original) +++ camel/trunk/camel-core/src/main/java/org/apache/camel/component/validator/DefaultLSResourceResolver.java Fri Dec 21 02:18:34 2012 @@ -50,6 +50,7 @@ public class DefaultLSResourceResolver i throw new IllegalArgumentException(String.format("Resource: %s refers an invalid resource without SystemId." + " Invalid resource has type: %s, namespaceURI: %s, publicId: %s, systemId: %s, baseURI: %s", resourceUri, type, namespaceURI, publicId, systemId, baseURI)); } + return new DefaultLSInput(publicId, systemId, baseURI); } @@ -64,11 +65,47 @@ public class DefaultLSResourceResolver i this.publicId = publicId; this.systemId = systemId; this.baseURI = baseURI; - + this.uri = getInputUri(); + } + + + private String getInputUri() { + // find the xsd with relative path + if (ObjectHelper.isNotEmpty(baseURI)) { + String inputUri = getUri(getRelativePath(baseURI)); + try { + ResourceHelper.resolveMandatoryResourceAsInputStream(camelContext.getClassResolver(), inputUri); + return inputUri; + } catch (IOException e) { + // ignore the exception + } + } + // don't use the relative path + return getUri(""); + } + + private String getRelativePath(String base) { + String userDir = ""; + String answer = ""; + if (ObjectHelper.isNotEmpty(base)) { + try { + userDir = FileUtil.getUserDir().toString(); + } catch (Exception ex) { + // do nothing here + } + // get the relative path from the userdir + if (ObjectHelper.isNotEmpty(base) && base.startsWith("file") && base.startsWith(userDir)) { + answer = FileUtil.onlyPath(base.substring(userDir.length())) + "/"; + } + } + return answer; + } + + private String getUri(String relativePath) { if (resourcePath != null) { - uri = resourcePath + "/" + systemId; + return FileUtil.onlyPath(resourceUri) + "/" + relativePath + systemId; } else { - uri = systemId; + return relativePath + systemId; } } @@ -164,4 +201,6 @@ public class DefaultLSResourceResolver i } } + + } Modified: camel/trunk/camel-core/src/main/java/org/apache/camel/util/FileUtil.java URL: http://svn.apache.org/viewvc/camel/trunk/camel-core/src/main/java/org/apache/camel/util/FileUtil.java?rev=1424788&r1=1424787&r2=1424788&view=diff ============================================================================== --- camel/trunk/camel-core/src/main/java/org/apache/camel/util/FileUtil.java (original) +++ camel/trunk/camel-core/src/main/java/org/apache/camel/util/FileUtil.java Fri Dec 21 02:18:34 2012 @@ -16,10 +16,13 @@ */ package org.apache.camel.util; + import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; +import java.net.URI; +import java.net.URISyntaxException; import java.nio.channels.FileChannel; import java.util.Iterator; import java.util.Locale; @@ -39,8 +42,149 @@ public final class FileUtil { private static final transient Logger LOG = LoggerFactory.getLogger(FileUtil.class); private static final int RETRY_SLEEP_MILLIS = 10; private static File defaultTempDir; - + + // current value of the "user.dir" property + private static String gUserDir; + // cached URI object for the current value of the escaped "user.dir" property stored as a URI + private static URI gUserDirURI; + // which ASCII characters need to be escaped + private static boolean gNeedEscaping[] = new boolean[128]; + // the first hex character if a character needs to be escaped + private static char gAfterEscaping1[] = new char[128]; + // the second hex character if a character needs to be escaped + private static char gAfterEscaping2[] = new char[128]; + private static char[] gHexChs = {'0', '1', '2', '3', '4', '5', '6', '7', + '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'}; + // initialize the above 3 arrays + static { + for (int i = 0; i <= 0x1f; i++) { + gNeedEscaping[i] = true; + gAfterEscaping1[i] = gHexChs[i >> 4]; + gAfterEscaping2[i] = gHexChs[i & 0xf]; + } + gNeedEscaping[0x7f] = true; + gAfterEscaping1[0x7f] = '7'; + gAfterEscaping2[0x7f] = 'F'; + char[] escChs = {' ', '<', '>', '#', '%', '"', '{', '}', + '|', '\\', '^', '~', '[', ']', '`'}; + int len = escChs.length; + char ch; + for (int i = 0; i < len; i++) { + ch = escChs[i]; + gNeedEscaping[ch] = true; + gAfterEscaping1[ch] = gHexChs[ch >> 4]; + gAfterEscaping2[ch] = gHexChs[ch & 0xf]; + } + } + private FileUtil() { + // Utils method + } + + + // To escape the "user.dir" system property, by using %HH to represent + // special ASCII characters: 0x00~0x1F, 0x7F, ' ', '<', '>', '#', '%' + // and '"'. It's a static method, so needs to be synchronized. + // this method looks heavy, but since the system property isn't expected + // to change often, so in most cases, we only need to return the URI + // that was escaped before. + // According to the URI spec, non-ASCII characters (whose value >= 128) + // need to be escaped too. + // REVISIT: don't know how to escape non-ASCII characters, especially + // which encoding to use. Leave them for now. + public static synchronized URI getUserDir() throws URISyntaxException { + // get the user.dir property + String userDir = ""; + try { + userDir = System.getProperty("user.dir"); + } catch (SecurityException se) { + } + + // return empty string if property value is empty string. + if (userDir.length() == 0) { + return new URI("file", "", "", null, null); + } + // compute the new escaped value if the new property value doesn't + // match the previous one + if (gUserDirURI != null && userDir.equals(gUserDir)) { + return gUserDirURI; + } + + // record the new value as the global property value + gUserDir = userDir; + + char separator = java.io.File.separatorChar; + userDir = userDir.replace(separator, '/'); + + int len = userDir.length(); + int ch; + StringBuffer buffer = new StringBuffer(len * 3); + // change C:/blah to /C:/blah + if (len >= 2 && userDir.charAt(1) == ':') { + ch = Character.toUpperCase(userDir.charAt(0)); + if (ch >= 'A' && ch <= 'Z') { + buffer.append('/'); + } + } + + // for each character in the path + int i = 0; + for (; i < len; i++) { + ch = userDir.charAt(i); + // if it's not an ASCII character, break here, and use UTF-8 encoding + if (ch >= 128) { + break; + } + if (gNeedEscaping[ch]) { + buffer.append('%'); + buffer.append(gAfterEscaping1[ch]); + buffer.append(gAfterEscaping2[ch]); + // record the fact that it's escaped + } else { + buffer.append((char)ch); + } + } + + // we saw some non-ascii character + if (i < len) { + // get UTF-8 bytes for the remaining sub-string + byte[] bytes = null; + byte b; + try { + bytes = userDir.substring(i).getBytes("UTF-8"); + } catch (java.io.UnsupportedEncodingException e) { + // should never happen + return new URI("file", "", userDir, null, null); + } + len = bytes.length; + + // for each byte + for (i = 0; i < len; i++) { + b = bytes[i]; + // for non-ascii character: make it positive, then escape + if (b < 0) { + ch = b + 256; + buffer.append('%'); + buffer.append(gHexChs[ch >> 4]); + buffer.append(gHexChs[ch & 0xf]); + } else if (gNeedEscaping[b]) { + buffer.append('%'); + buffer.append(gAfterEscaping1[b]); + buffer.append(gAfterEscaping2[b]); + } else { + buffer.append((char)b); + } + } + } + + // change blah/blah to blah/blah/ + if (!userDir.endsWith("/")) { + buffer.append('/'); + } + + gUserDirURI = new URI("file", "", buffer.toString(), null, null); + + return gUserDirURI; } /** Added: camel/trunk/camel-core/src/test/java/org/apache/camel/component/validator/ValidatorIncludeRelativeRouteTest.java URL: http://svn.apache.org/viewvc/camel/trunk/camel-core/src/test/java/org/apache/camel/component/validator/ValidatorIncludeRelativeRouteTest.java?rev=1424788&view=auto ============================================================================== --- camel/trunk/camel-core/src/test/java/org/apache/camel/component/validator/ValidatorIncludeRelativeRouteTest.java (added) +++ camel/trunk/camel-core/src/test/java/org/apache/camel/component/validator/ValidatorIncludeRelativeRouteTest.java Fri Dec 21 02:18:34 2012 @@ -0,0 +1,66 @@ +/** + * 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.apache.camel.ValidationException; +import org.apache.camel.builder.RouteBuilder; +import org.apache.camel.component.mock.MockEndpoint; + +public class ValidatorIncludeRelativeRouteTest extends ValidatorIncludeRouteTest { + + public void testValidMessage() throws Exception { + validEndpoint.expectedMessageCount(1); + finallyEndpoint.expectedMessageCount(1); + + 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("direct:start", body); + + MockEndpoint.assertIsSatisfied(validEndpoint, invalidEndpoint, finallyEndpoint); + } + + @Override + protected RouteBuilder createRouteBuilder() throws Exception { + return new RouteBuilder() { + @Override + public void configure() throws Exception { + from("direct:start") + .doTry() + .to("validator:org/apache/camel/component/validator/xsds/person.xsd") + .to("mock:valid") + .doCatch(ValidationException.class) + .to("mock:invalid") + .doFinally() + .to("mock:finally") + .end(); + } + }; + } + +} Added: camel/trunk/camel-core/src/test/resources/org/apache/camel/component/validator/xsds/health/common/common.xsd URL: http://svn.apache.org/viewvc/camel/trunk/camel-core/src/test/resources/org/apache/camel/component/validator/xsds/health/common/common.xsd?rev=1424788&view=auto ============================================================================== --- camel/trunk/camel-core/src/test/resources/org/apache/camel/component/validator/xsds/health/common/common.xsd (added) +++ camel/trunk/camel-core/src/test/resources/org/apache/camel/component/validator/xsds/health/common/common.xsd Fri Dec 21 02:18:34 2012 @@ -0,0 +1,14 @@ +<?xml version="1.0" encoding="UTF-8"?> +<xs:schema + attributeFormDefault="unqualified" + elementFormDefault="qualified" + targetNamespace="org.health.check.common" + xmlns:xs="http://www.w3.org/2001/XMLSchema"> + <xs:element name="commonElement" type="common:commonType" xmlns:common="org.health.check.common"/> + <xs:complexType name="commonType"> + <xs:sequence> + <xs:element type="xs:string" name="element1"/> + <xs:element type="xs:string" name="element2"/> + </xs:sequence> + </xs:complexType> +</xs:schema> \ No newline at end of file Added: camel/trunk/camel-core/src/test/resources/org/apache/camel/component/validator/xsds/health/health.xsd URL: http://svn.apache.org/viewvc/camel/trunk/camel-core/src/test/resources/org/apache/camel/component/validator/xsds/health/health.xsd?rev=1424788&view=auto ============================================================================== --- camel/trunk/camel-core/src/test/resources/org/apache/camel/component/validator/xsds/health/health.xsd (added) +++ camel/trunk/camel-core/src/test/resources/org/apache/camel/component/validator/xsds/health/health.xsd Fri Dec 21 02:18:34 2012 @@ -0,0 +1,18 @@ +<?xml version="1.0" encoding="UTF-8"?> +<xs:schema + attributeFormDefault="unqualified" + elementFormDefault="qualified" + targetNamespace="org.health.check.person" + xmlns:xs="http://www.w3.org/2001/XMLSchema" + xmlns:common="org.health.check.common"> + <xs:import schemaLocation="common/common.xsd" namespace="org.health.check.common"/> + <xs:element name="health" type="org:healthType" xmlns:org="org.health.check.person"/> + + <xs:complexType name="healthType"> + <xs:sequence> + <xs:element type="xs:string" name="lastCheck"/> + <xs:element type="xs:string" name="status"/> + <xs:element ref="common:commonElement" maxOccurs="1" minOccurs="0"/> + </xs:sequence> + </xs:complexType> +</xs:schema> \ No newline at end of file Added: camel/trunk/camel-core/src/test/resources/org/apache/camel/component/validator/xsds/person.xsd URL: http://svn.apache.org/viewvc/camel/trunk/camel-core/src/test/resources/org/apache/camel/component/validator/xsds/person.xsd?rev=1424788&view=auto ============================================================================== --- camel/trunk/camel-core/src/test/resources/org/apache/camel/component/validator/xsds/person.xsd (added) +++ camel/trunk/camel-core/src/test/resources/org/apache/camel/component/validator/xsds/person.xsd Fri Dec 21 02:18:34 2012 @@ -0,0 +1,20 @@ +<?xml version="1.0" encoding="UTF-8"?> +<xs:schema attributeFormDefault="unqualified" + elementFormDefault="qualified" + xmlns:xs="http://www.w3.org/2001/XMLSchema" + xmlns:p="org.person" + targetNamespace="org.person" + xmlns:h="org.health.check.person"> + <xs:import schemaLocation="health/health.xsd" namespace="org.health.check.person"/> + <xs:element name="person" type="p:personType"> +</xs:element> +<xs:complexType name="personType"> + <xs:sequence> + <xs:element type="xs:string" name="firstName"/> + <xs:element type="xs:string" name="lastName"/> + <xs:element type="xs:string" name="city"/> + <xs:element ref="h:health" maxOccurs="1" minOccurs="0"/> + </xs:sequence> + <xs:attribute type="xs:string" name="user"/> +</xs:complexType> +</xs:schema> \ No newline at end of file