package org.korsakow.diagnostics;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.channels.FileChannel;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashSet;
import java.util.Scanner;
import java.util.Set;
import java.util.concurrent.atomic.AtomicReference;
import java.util.logging.FileHandler;
import java.util.logging.Logger;
import java.util.logging.SimpleFormatter;
public class QTJavaHelp
{
private static final Logger logger = Logger.getLogger( QTJavaHelp.class.getName() );
private static boolean printDisclaimer() throws IOException {
System.out.println( ""
+ "contact: contact@korsakow.org"
+ "\n"
+ "\nQTJavaHelp is designed to diagnose installations of Java and Quicktime and"
+ "\nto possibly fix them."
+ "\n"
+ "\n* This software does not send any information anywhere, to anyone and doesn't do *"
+ "\n* anything to your system without your permission. *"
+ "\n* Here's what it does do, if you let it:"
+ "\n - Ask you before making any changes to your system"
+ "\n - Look for files"
+ "\n - Copy files from one place on your disk to another"
+ "\n - Log everything it does to a file called qjavathelp.log"
+ "\n - "
+ "\n* That said, don't sue me if it all goes horribly wrong somehow. *"
+ "\n"
+ "\n* If you can live with that type y and press enter, anything else will quit. *"
+ "\n"
+ "\n" );
return Util.okay();
}
public static void main( String[] args ) throws Throwable {
// if ( !Util.isWindowsOS() ) {
// System.out.println( "This program is only designed to be run on windows." );
// return;
// }
try {
System.setProperty( "log4j.configuration", "ql.log4j.properties" );
if ( !printDisclaimer() ) {
System.out.println( "Bye." );
return;
}
QTJavaHelp qtl = new QTJavaHelp();
qtl.execute();
} catch ( Throwable t ) {
logger.throwing( "", "", t );
throw t;
}
}
public static Set<File> getDefaultJavaRoots() {
Set<File> files = new HashSet<File>();
if( Util.isMacOS() ) {
for ( String filename : Arrays.asList(
"/System/Library/Java/"
) ) {
files.add( new File( filename ) );
}
} else
if ( Util.isWindowsOS() ) {
for ( String filename : Arrays.asList(
"c:/program files",
"c:/program files (x86)"
) ) {
files.add( new File ( filename ) );
}
}
return files;
}
public static String getJavaExecutableName() {
if ( Util.isWindowsOS() ) return "java.exe";
return "java";
}
public QTJavaHelp() throws IOException {
final FileHandler handler = new FileHandler( "qtjavahelp.log", 500 * 1024, 1 );
handler.setFormatter( new SimpleFormatter() );
logger.addHandler( handler );
}
public void execute() throws IOException {
logger.info( "QTJavaHelp starting up..." );
Set<File> roots = getDefaultJavaRoots();
logger.info( "Searching recursively in: " + Util.join( roots, "," ) );
logger.info( "Locating Java..." );
final AtomicReference<Set<File>> missingExtDirs = new AtomicReference<Set<File>>( new HashSet<File>() );
final AtomicReference<Set<File>> javaExtDirs = new AtomicReference<Set<File>>( new HashSet<File>() );
final AtomicReference<Set<File>> javaHomeDirs = new AtomicReference<Set<File>>( new HashSet<File>() );
final AtomicReference<Integer> counter = new AtomicReference<Integer>( 0 );
final AtomicReference<Integer> marker = new AtomicReference<Integer>( 0 );
for ( File root : roots )
Util.visitRecursively( root, new FileVisitor() {
@Override public void visit( File file ) {
char markers[] = { '.', 'o','O','o' };
char mark = '.';
if ( file.getName().equals( getJavaExecutableName() ) ) {
File parent = file.getParentFile();
if ( parent == null ) return;
parent = parent.getParentFile(); // bin/../
if ( parent == null ) return;
javaHomeDirs.get().add( parent );
File ext = new File( parent, "lib/ext" );
if ( ext.isDirectory() )
javaExtDirs.get().add( ext );
Set<File> extFiles = new HashSet<File>();
if ( ext.listFiles() != null )
extFiles.addAll( Arrays.asList( ext.listFiles() ) );
Set<File> tmp = new HashSet<File>();
for ( File extFile : extFiles )
if ( extFile.getName().equalsIgnoreCase( "qtjava.zip" ) ) {
tmp.add( extFile );
}
if ( tmp.isEmpty() )
missingExtDirs.get().add( ext );
if ( counter.get() % 1 == 0 ) {
mark = markers[ marker.get() % markers.length ];
marker.set( marker.get() + 1 );
System.out.print( mark );
if ( marker.get() % ( 80 - 9 ) == 0 )
System.out.println( " d( o.o )b" );
}
counter.set( counter.get() + 1 );
}
}
});
if ( javaHomeDirs.get().isEmpty() ) {
logger.info( "Could not locate Java, it must be in a non-standard location; giving up =(" );
return;
}
logger.info( "Found java here: " + Util.join( javaHomeDirs.get(), "," ) );
if ( missingExtDirs.get().isEmpty() ) {
logger.info( "It looks like everything is okay; giving up!" );
return;
}
logger.info( "But these ones were missing qtjava: " + Util.join( missingExtDirs.get(), "," ) );
logger.info( "Locating qtjava ( Quicktime for Java )..." );
Set<File> qtjavas = Util.find( roots, "qtjava.zip" );
if ( qtjavas.isEmpty() ) {
logger.info( "Quicktime for Java was not found; giving up =(" );
return;
}
logger.info( "Found qtjava.zip here: " + Util.join( qtjavas, "," ) );
logger.info( "So it looks like your Java installation can be fixed by copying qtjava over into it. If you're okay with this type y and press enter; anything else will bail out." );
if ( !Util.okay() )
return;
logger.info( "Copying qtjava into Java installation directories..." );
File qtjava = qtjavas.iterator().next(); // I guess we don't care which?
Set<IOException> exceptions = new HashSet<IOException>();
for ( File extDir : missingExtDirs.get() ) {
try {
final File toFile = new File( extDir, qtjava.getName() );
logger.info( String.format( "Copying '%s' to '%s'", qtjava.getPath(), toFile.getPath() ) );
if ( toFile.exists() ) {
logger.info( String.format( "'%s' already exists, skipping", toFile.getPath() ) );
continue;
}
Util.copyFile( qtjava, toFile );
} catch (IOException e) {
exceptions.add( e );
}
}
if ( !exceptions.isEmpty() ) {
Set<String> msgs = new HashSet<String>();
for ( Exception e : exceptions )
msgs.add( e.getMessage() );
logger.info( "Some problems happened during the copy: '" + Util.join( msgs, "', '" ) + "'" );
} else {
logger.info( "All done; huh, it looks like everything went okay." );
}
}
}
interface FileVisitor
{
void visit( File file );
}
class Util
{
private static final Logger logger = Logger.getLogger( Util.class.getName() );
public static boolean okay() throws IOException {
return okay(false);
}
public static boolean okay(boolean picky) throws IOException {
Scanner scanner = new Scanner( System.in );
do {
System.out.print( "Okay? y/n: " );
String s = scanner.nextLine();
if ( s.equalsIgnoreCase( "y" )) {
System.out.println();
return true;
} else if ( s.equalsIgnoreCase( "n" ) ) {
System.out.println();
return false;
} else {
System.out.println();
}
} while ( picky );
return false;
}
public static void visitRecursively( File parent, FileVisitor visitor ) throws IOException {
visitRecursively(parent, visitor, new HashSet<String>());
}
private static void visitRecursively( File parent, FileVisitor visitor, Set<String> visited ) throws IOException {
String canon = parent.getCanonicalPath();
if (visited.contains(canon))
return;
visited.add(canon);
visitor.visit( parent );
File[] children = parent.listFiles();
if ( children != null )
for ( File child : children )
visitRecursively( child, visitor, visited );
}
public static Set<File> find( final Collection<File> roots, final String name ) throws IOException {
final AtomicReference<Integer> counter = new AtomicReference<Integer>( 0 );
final AtomicReference<Integer> marker = new AtomicReference<Integer>( 0 );
final AtomicReference<Set<File>> files = new AtomicReference<Set<File>>( new HashSet<File>() );
FileVisitor visitor = new FileVisitor() {
@Override public void visit(File file) {
char markers[] = { '.', 'o','O','o' };
char mark = '.';
if ( counter.get() % 5000 == 0 ) {
mark = markers[ marker.get() % markers.length ];
marker.set( marker.get() + 1 );
System.out.print( mark );
if ( marker.get() % ( 80 - 9 ) == 0 )
System.out.println( " d( o.o )b" );
}
counter.set( counter.get() + 1 );
if ( file.getName().equalsIgnoreCase( name ) )
files.get().add( file );
}
};
for ( File root : roots )
visitRecursively( root, visitor );
System.out.println();
logger.info( String.format( "Finished searching through %d fliles", counter.get() ) );
return files.get();
}
public static String join(Collection<?> coll, String glue)
{
StringBuilder builder = new StringBuilder();
for (Object o : coll) {
builder.append(o.toString()).append(glue);
}
if (builder.length() > 0)
builder.delete(builder.length() - glue.length(), builder.length());
return builder.toString();
}
public static boolean isWindowsOS()
{
final String osName = System.getProperty("os.name", "unknown").toLowerCase();
return osName.startsWith("windows");
}
public static boolean isMacOS()
{
final String osName = System.getProperty("os.name", "unknown").toLowerCase();
return osName.startsWith("mac") || osName.contains("darwin");
}
public static void copyFile(File sourceFile, File destFile) throws IOException
{
if (destFile.getParentFile() != null)
destFile.getParentFile().mkdirs();
FileInputStream input = null;
FileOutputStream output = null;
try {
input = new FileInputStream(sourceFile);
output = new FileOutputStream(destFile);
long offset = 0;
long length = sourceFile.length();
long count = length;
final FileChannel destChannel = output.getChannel();
final FileChannel srcChannel = input.getChannel();
do {
long written = destChannel.transferFrom(srcChannel, offset, count);
count -= written;
offset += written;
} while (count > 0);
} finally {
if (input != null) try { input.close(); } catch (IOException e) {}
if (output != null) try { output.close(); } catch (IOException e) {}
}
}
}