Willem what's all the code in FileUtil.
At first glance this doesn't look to good, and easy to support such code.

I would like to find a better solution.
And why is this only related to validator component?

Can we look at another solution that doesn't require adding a lot of weird code?



On Fri, Dec 21, 2012 at 3:18 AM,  <ningji...@apache.org> wrote:
> 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
>
>



-- 
Claus Ibsen
-----------------
Red Hat, Inc.
FuseSource is now part of Red Hat
Email: cib...@redhat.com
Web: http://fusesource.com
Twitter: davsclaus
Blog: http://davsclaus.com
Author of Camel in Action: http://www.manning.com/ibsen

Reply via email to