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


Reply via email to