Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Run GroovyModuleLoaderExample in IDEA , Win7 Path error #40

Open
ahypnos opened this issue Mar 6, 2015 · 11 comments
Open

Run GroovyModuleLoaderExample in IDEA , Win7 Path error #40

ahypnos opened this issue Mar 6, 2015 · 11 comments

Comments

@ahypnos
Copy link

ahypnos commented Mar 6, 2015

Exception in thread "main" java.nio.file.InvalidPathException: Illegal char <:> at index 2: /C:/Users/ahypnos/.gradle/caches/modules-2/files-2.1/org.codehaus.groovy/groovy-all/2.3.6/dfe5f424777f4579786ec2145fc43286fcda8195/groovy-all-2.3.6.jar
    at sun.nio.fs.WindowsPathParser.normalize(WindowsPathParser.java:182)
    at sun.nio.fs.WindowsPathParser.parse(WindowsPathParser.java:153)
    at sun.nio.fs.WindowsPathParser.parse(WindowsPathParser.java:77)
    at sun.nio.fs.WindowsPath.parse(WindowsPath.java:94)
    at sun.nio.fs.WindowsFileSystem.getPath(WindowsFileSystem.java:255)
    at java.nio.file.Paths.get(Paths.java:84)
    at com.netflix.nicobar.core.utils.ClassPathUtils.getJarPathFromUrl(ClassPathUtils.java:114)
    at com.netflix.nicobar.core.utils.ClassPathUtils.findRootPathForResource(ClassPathUtils.java:73)
    at com.netflix.nicobar.example.groovy2.ExampleResourceLocator.getGroovyRuntime(ExampleResourceLocator.java:50)
    at com.netflix.nicobar.example.groovy2.GroovyModuleLoaderExample.runExample(GroovyModuleLoaderExample.java:73)
    at com.netflix.nicobar.example.groovy2.GroovyModuleLoaderExample.main(GroovyModuleLoaderExample.java:67)
@hastebrot
Copy link

I get the same exception. This is due to the : after the drive letter. This is due to the / before the drive letter.

@hastebrot
Copy link

We need to replace "/C:/..." with "C:/...".

import java.nio.file.Path;
import java.nio.file.Paths;

import org.apache.commons.io.FileUtils;

public class WindowsPathIssue {
    public static void main(String[] args) {
        Path pathToNotepad = Paths.get("/C:/Windows/notepad.exe");
        System.out.println(FileUtils.sizeOf(pathToNotepad.toFile()));
    }
}

@hastebrot
Copy link

Here is a test case for ClassPathUtilsTest. Note that both assertions fail on a Windows machine, because the first call to getJarPathFromUrl() returns a path with \ as path separator.

@Test
public void testGetJarPathFromUrl() throws Exception {
    URL posixPath = new URL("jar:file:/path/to/groovy.jar!/path/to/resource.txt");
    URL windowsPath = new URL("jar:file:/C:/path/to/groovy.jar!/path/to/resource.txt");
    assertEquals(ClassPathUtils.getJarPathFromUrl(posixPath).toString(), "/path/to/groovy.jar");
    assertEquals(ClassPathUtils.getJarPathFromUrl(windowsPath).toString(), "C:/path/to/groovy.jar");
}

@hastebrot
Copy link

Hmm, seems that we can't influence how Paths.get() handles path separators under Windows. 😢

System.out.println(Paths.get("/foo/bar")); // outputs "\foo\bar".

@hastebrot
Copy link

This code should solve the issue:

@Test
public void testGetJarPathFromUrl() throws Exception {
    // Regression tests for https://github.com/Netflix/Nicobar/issues/40.
    URL pathOnPosix = new URL("jar:file:/path/to/groovy.jar!/path/to/resource.txt");
    URL pathOnWindows = new URL("jar:file:/C:/path/to/groovy.jar!/path/to/resource.txt");
    URL pathWithSpaces = new URL("jar:file:/D:/path to/groovy.jar!/path to/resource.txt");
    assertEquals("/path/to/groovy.jar",
        ClassPathUtils.getJarPathFromUrl(pathOnPosix).toString().replace("\\", "/"));
    assertEquals("C:/path/to/groovy.jar",
        ClassPathUtils.getJarPathFromUrl(pathOnWindows).toString().replace("\\", "/"));
    assertEquals("D:/path to/groovy.jar",
        ClassPathUtils.getJarPathFromUrl(pathWithSpaces).toString().replace("\\", "/"));
}

Version 1:

public static Path getJarPathFromUrl(URL jarUrl) {
    String jarPath = jarUrl.getPath();
    int startIndex = jarPath.startsWith("file:") ? 5 : 0;
    int endIndex = jarPath.lastIndexOf("!");
    String jarFilePath = jarPath.substring(startIndex, endIndex);
    return Paths.get(new File(jarFilePath).getPath());
}

Version 2:

public static Path getJarPathFromUrl(URL jarUrl) {
    try {
        JarURLConnection connection = (JarURLConnection) jarUrl.openConnection();
        URL jarFileUrl = connection.getJarFileURL();
        String jarFilePath = new File(jarFileUrl.toURI()).getPath();
        return Paths.get(jarFilePath);
    }
    catch (Exception exception) {
        throw new RuntimeException(exception);
    }
}

@hastebrot
Copy link

There is another exception with ArchiveRepositoryPoller and Paths.get(). The poller wants Paths to handle Windows paths with : in the file name:

java.nio.file.InvalidPathException: Illegal char <:> at index 10: HelloWorld:1428014423748

@hastebrot
Copy link

The class org.jboss.modules.ModuleIdentifier contains following method, which is used by JBossModuleUtils.createRevisionId() and generates the revision ID, i.e. HelloWorld:1428014423748.

public String toString() {
    return name + ":" + slot;
}

@hastebrot
Copy link

My suggestion is, to add a wrapper method for Paths.get() into ClassPathUtils and substitute all calls to Paths.get() with the wrapper method:

public static Path getPath(String pathString) {
    File pathFile = new File(pathString);
    return Paths.get(pathFile.getParent(), pathFile.getName().replace(":", "_"));
}

With this approach I finally managed to get the GroovyModuleLoaderExample up and running under Windows:

Received module update event. newModule: JBossScriptModule[moduleId=HelloWorld,jbossModule=Module "HelloWorld:1428015308052" from JBossModuleLoader@7d51eec1 for finders [com.netflix.nicobar.core.module.jboss.JBossModuleLoader$2@34ee2917],createTime=1428015307902,sourceArchive=JarScriptArchive[moduleSpec=ScriptModuleSpec[moduleId=HelloWorld,archiveMetadata={metadataName1=metadataValue1, metadataName2=metadataValue2},compilerPlugins=[groovy2],dependencies=[]],entryNames=[HelloWorld.groovy, META-INF/MANIFEST.MF],rootUrl=file:/C:/Users/benjamin/AppData/Local/Temp/GroovyModuleLoaderExample5391775305424158668/HelloWorld.jar,createTime=1428015307902]],  oldModule: null
2683 [main] WARN com.netflix.config.sources.URLConfigurationSource - No URLs will be polled as dynamic configuration sources.
2683 [main] INFO com.netflix.config.sources.URLConfigurationSource - To enable URLs as dynamic configuration sources, define System property archaius.configurationSource.additionalUrls or make config.properties available on classpath.
2685 [main] INFO com.netflix.config.DynamicPropertyFactory - DynamicPropertyFactory is initialized with configuration sources: com.netflix.config.ConcurrentCompositeConfiguration@3a82f6ef
Module(s) have been executed. Output: [Hello, World!]

@whisperwing
Copy link

@hastebrot did you run into problem with the example if you update jar file at runtime?

@hastebrot
Copy link

@whisperwing I haven't tested this, yet.

@whisperwing
Copy link

@hastebrot I found that replacing jar file without name change wouldn't work. Likely because of #37

vasanth-asokan pushed a commit that referenced this issue Oct 5, 2015
Fixing Windows compatibility #40
bruceasu pushed a commit to bruceasu/Nicobar that referenced this issue Dec 19, 2018
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants