views:

642

answers:

5

Hello all,

I'm currently working on a web application that involves mounting a drive and extracting a tar.gz file, all in Java. Since the application runs in a linux environment, I figured I'd try using unix commands like "mount" and "tar".

Runtime runtime = Runtime.getRuntime();
Process proc;

String mountCommand = "mount -t cifs -o username=...";
String extractCommand = "tar xzf ..."

proc = runtime.exec(mountCommand);
proc.waitFor();

proc = runtime.exec(extractCommand);
proc.waitFor();

Running the mount command and extract command in the terminal works fine, but fails when FIRST run in java. The second proc.waitFor() returns exit code 2. However, running this code after the first failed attempt works fine. I have a feeling that the problem is that waitFor() isn't waiting until the mount command is fully completed. Am I missing anything important in my code?

Also, I'd rather do this all in Java, but I had a really hard time figuring out how to untar a file, so I'm taking this approach. (oh if anyone can tell me how to do this i would be very happy). Any suggestions would be muuuuuuuuuuch appreciated!

A: 

Take a look at the org.apache.tools.tar package in the Ant codebase. There is a class in that package, TarInputStream, that can be used to read tar archives.

Brandon E Taylor
Yeah that seems like the way to go, I just couldn't figure out how to preserve last modified dates on the extracted files when using that.
Matthew
A: 

It may be related to the way you call the method.

See this answer

Basically try using

.exec( String [] command );

instead of

.exec( String command );

I'm not sure if it is even related, because you mention it runs the second time. Give it a try and let us know.

OscarRyz
Thanks for the input, but this doesn't seem to work. From what I've read, this just calls one exec after another without waiting for each process to finish.
Matthew
:( Too sad. Well , no what it actually does is to accurately separate the arguments. So "command parameter option option" is transformed in 4 parts ( command, parameter, option, option ) and that's it. Sometimes passing arguments are somehow in the wrong order and it sends "command parameter" "option option" using two string instead of 4.
OscarRyz
A: 

This can all be done in Java, but you have to be aware of caveats when dealing with native processes.

The waitFor() command may not be doing what you hope: if the process you started has a child process that does the actual work you need then the waitFor(), which returns when the parent process has finished, has not allowed enough time for the child process to finish.

One way to get around this is to loop over some test to see that the native processes you started have finished to your satisfaction---in this case perhaps checking if some java.io.File exists.

Glenn
Ah, that makes sense. Using that File trick would work, but it feels so hackish... I think I'll look into the Java libraries a little more before I resort to that.
Matthew
+2  A: 

Quick Answer

Since a dependency on external commands exists, simplify it like this:

#!/bin/bash
mount -t cifs -o username=...
tar xzf ...

Name it mount-extract.sh then call it using a single Runtime.exec() call.

Semi-integrated Answer

Use Java APIs.

You will need Runtime.exec to execute the mount command.

Forward Looking

Since Java is a cross-platform software development tool, consider abstracting the mount command in your application to be derived dynamically based on the underlying operating system.

See: http://stackoverflow.com/questions/208839/how-can-i-mount-a-windows-drive-in-java

See: http://java.sun.com/j2se/1.4.2/docs/api/java/lang/System.html#getProperties()

Of course, Agile development would insist that this not be done until it is needed. So keep it in the back of your mind until then (as you might never run the application on anything but Unix-based systems).

Dave Jarvis
Very helpful, thanks a lot. I just tried the first quick method, but it failed due to the same problem. The bash script didn't wait until the mount finished before executing the tar command and the program blew up. I'm going to make a second try at extracting with Java. I actually tried using a tar library earlier, but couldnt figure out how to preserve last modified dates in the extracted files so I gave up. There's gotta be an easy way to do that.. There is also an SMB library (jcifs.samba.org) that seems pretty promising.
Matthew
Now you know something you didn't earlier: the mount command exits before it finishes. Another solution is to use sleep and loop until the file can be read (or a fixed number of iterations have passed).
Dave Jarvis
A: 

Making progress. In case anyone was wondering, here is how I am extracting a tar.gz file in Java. Put together from a few online tutorials.

public static void extract(String tgzFile, String outputDirectory)
    throws Exception {

// Create the Tar input stream.
FileInputStream fin = new FileInputStream(tgzFile);
GZIPInputStream gin = new GZIPInputStream(fin);
TarInputStream tin = new TarInputStream(gin);

// Create the destination directory.
File outputDir = new File(outputDirectory);
outputDir.mkdir();

// Extract files.
TarEntry tarEntry = tin.getNextEntry();
while (tarEntry != null) {
    File destPath = new File(outputDirectory + File.separator + tarEntry.getName());

    if (tarEntry.isDirectory()) {
 destPath.mkdirs();
    } else {
 // If the parent directory of a file doesn't exist, create it.
 if (!destPath.getParentFile().exists())
     destPath.getParentFile().mkdirs();

 FileOutputStream fout = new FileOutputStream(destPath);
 tin.copyEntryContents(fout);
 fout.close();
    // Presserve the last modified date of the tar'd files.
 destPath.setLastModified(tarEntry.getModTime().getTime());
    }
    tarEntry = tin.getNextEntry();
}
tin.close();
}
Matthew