views:

156

answers:

7

I know. Heresy. But I'm in a bind. I have a lot of config files that use absolute path names, which creates an incompatibility between OS X and Windows. If I can get OS X (which I'm betting is the more flexible of the two) to recognize "Q:/foo/bar/bim.properties" as a valid absolute file name, it'll save me days of work spelunking through stack traces and config files.

In the end, I need this bit of Java test code to print "SUCCESS!" when it runs:

import java.io.*;
class DriveLetterTest {
  static public void main(String... args) {
    File f = new File("S:");
    if (f.isDirectory()) {
      System.out.println("SUCCESS!");
    }
    else {
      System.out.println("FAIL!");
    }
  }
}

Anyone know how this can be done?

UPDATE: Thanks for all the feeback, everyone. It's now obvious to me I really should have been clearer in my question.

Both the config files and the code that uses them belong to a third-party package I cannot change. (Well, I can change them, but that means incurring an ongoing maintenance load, which I want to avoid if at all possible.)

I'm in complete agreement with all of you who are appalled by this state of affairs. But the fact remains: I can't change the third-party code, and I really want to avoid forking the config files.

+1  A: 

Most likely you'd have to provide a different java.io.File implementation that can parse out the file paths correctly, maybe there's one someone already made. The real solution is to put this kind of stuff (hard-coded file paths) in configuration files and not source code.

Gary
DeathB4Decaf
I agree. You should have such fix coded paths in your application. Avoid them by relative-paths, using wll defined directories or putting the paths into configuration files.
Gamlor
Are you willing to provide a new File implementation but not change your text config files? :-/
OscarRyz
I think you should change your config files.
Gary
The config files are part of a third-party package I don't control. I *could* modify them, but that would mean essentially forking that package, and accepting the maintenance burden of keeping my configs in sync with the trunk line.In this case, I'm willing to consider tweaking java.io.File because it imposes very little ongoing maintenance load. It's a hack, but it's a little one that only affects me, and only when I upgrade my JVM. Trying to modify the parsing code or config files means daily headaches every time someone else on the team adds new config properties/changes.
DeathB4Decaf
or instead of providing an alternate File implementation, if you have access to the source just make a wrapper object that does the translation for you and put it in place of 'File'.
Gary
+1  A: 

Just tested something out, and discovered something interesting: In Windows, if the current directory is on the same logical volume (i.e. root is the same drive letter), you can leave off the drive letter when using a path. So you could just trim off all those drive letters and colons and you should be fine as long as you aren't using paths to items on different disks.

JAB
+3  A: 
Yuji
I would be pissed if I installed some software that littered my filesystem with symlinks like this!
fuzzy lollipop
I know, I know ... :p But I just provided the OP the simplest of all solutions! OK I added extra instructions to hide files from Finder :p
Yuji
bad advice is worse than no advice, this isn't simple it is a worst practice anti-pattern hack in the worst way, shame on you for even suggesting it
fuzzy lollipop
If OP can't use different config files per OS, I think it would be harder to create symbolic links.
OscarRyz
Yes all of you are perfectly right...
Yuji
point given for seeing the error of your ways :-)
fuzzy lollipop
+3  A: 

Short answer: No.
Long answer: For Java you should use System.getProperties(XXX). Then you can load a Properties file or Configuration based on what you find in os.name.
Alternate Solution just strip off the S: when you read the existing configuration files on non-Windows machines and replace them with the appropriate things.
Opinion: Personally I would bite the bullet and deal with the technical debt now, fix all the configuration files at build time when the deployment for OSX is built and be done with it.

public class WhichOS
{
    public static void main(final String[] args)
    {
        System.out.format("System.getProperty(\"os.name\") = %s\n", System.getProperty("os.name"));
        System.out.format("System.getProperty(\"os.arch\") = %s\n", System.getProperty("os.arch"));
        System.out.format("System.getProperty(\"os.version\") = %s\n", System.getProperty("os.version"));
    }
}

the output on my iMac is:

System.getProperty("os.name") = Mac OS X
System.getProperty("os.arch") = x86_64
System.getProperty("os.version") = 10.6.4
fuzzy lollipop
I think in this case the "Long answer" is the "Sane answer" - use different configurations for a different OS.
matt b
I totally agree with everything you've said. My own code is built without hard-coded file names, doesn't care what OS it's running on, where in the filesystem it lives, etc.Alas, the code that parses the paths is third-party code I can't touch. And the config files have to work on both OS X and Windows. So the only options I have left are tweaking OS X to effectively symlink drive letters to dirs, or tweak the java.io.File implementation.
DeathB4Decaf
+1  A: 

If you are not willing to change your config file per OS, what are they for in first place?

Every installation should have its own set of config files and use it accordingly.

But if you insist.. you just have to detect the OS version and if is not Windows, ignore the letter:

Something along the lines:

boolean isWindows = System.getProperty("os.name")
                     .toLowerCase().contains("windows"); 

String folder = "S:";
if( isWindows && folder.matches("\\w:") {
     folder = "/";
 } else if( isWindows && folder.matches("\\w:.+")) {
     folder = folder.substring(2);// ignoring the first two letters S:
 }

You get the idea

OscarRyz
+1  A: 

The only way you can replace java.io.File is to replace that class in rt.jar.

I don't recommend that, but the best way to do this is to grab a bsd-port of the OpenJDK code, make necessary changes, build it and redistribute the binary with your project. Write a shell script to use your own java binary and not the built-in one.

PS. Just change your config files! Practice your regex skills and save yourself a lot of time.

tulskiy
+1  A: 

Here's what I finally ended up doing:

I downloaded the source code for the java.io package, and tweaked the code for java.io.File to look for path names that start with a letter and a colon. If it finds one, it prepends "/Volumes/" to the path name, coughs a warning into System.err, then continues as normal.

I've added symlinks under /Volumes to the "drives" I need mapped, so I have:

  • /Volumes/S:
  • /Volumes/Q:

I put it into its own jar, and put that jar at the front of the classpath for this project only. This way, the hack affects only me, and only this project.

Net result: java.io.File sees a path like "S:/bling.properties", and then checks the OS. If the OS is OS X, it prepends "/Volumes/", and looks for a file in /Volumes/S:/bling.properties, which is fine, because it can just follow the symlink.

Yeah, it's ugly as hell. But it gets the job done for today.

DeathB4Decaf
haha, you're welcome :-). Glad to hear it worked, I've never done something like that!
Gary
Ah, I should post an addendum here. I had to put the symlinks under ~/Drives/, since OS X kept cleaning them out of /Volumes.
DeathB4Decaf
it might be slightly less awful if you avoided the global symlinks and used a user directory. Like when you said you wanted "~/workspace".
Gary
Gary, you're quite right. See my addendum above, where I note that I put them under ~/Drives.
DeathB4Decaf