Created
October 30, 2014 14:03
-
-
Save RavuAlHemio/0dd8bbefd21f2e7cbf91 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package ds3; | |
import java.io.BufferedReader; | |
import java.io.EOFException; | |
import java.io.FileNotFoundException; | |
import java.io.FileReader; | |
import java.io.IOException; | |
import java.io.InputStreamReader; | |
import java.lang.reflect.Method; | |
import java.lang.reflect.InvocationTargetException; | |
import java.security.KeyPair; | |
import java.security.PrivateKey; | |
import java.security.PublicKey; | |
import org.apache.log4j.Logger; | |
import org.bouncycastle.openssl.PEMReader; | |
import org.bouncycastle.openssl.PasswordFinder; | |
/** | |
* Abstract base class for programs' main classes. | |
* | |
* @author Ondřej Hošek | |
*/ | |
public abstract class MainClass | |
{ | |
/** The logger for this class. */ | |
private static Logger l = Logger.getLogger(MainClass.class); | |
/** Array of strings detected as cries for help on the command line. */ | |
protected static final String[] HELP_STRINGS = { | |
"--help", | |
"-h", | |
"-?" | |
}; | |
/** | |
* Checks the number of commandline arguments as well as requests for help. | |
* May call System.exit(). | |
* | |
* @param args Command-line arguments as specified by the user. | |
* @param expectedNum Expected number of arguments. | |
*/ | |
public static void checkArgs(String[] args, int expectedNum, Class<?> mainClass) | |
{ | |
if (args.length > 0) | |
{ | |
for (String s : HELP_STRINGS) | |
{ | |
if (args[0].equals(s)) | |
{ | |
callUsage(mainClass); | |
System.exit(0); | |
} | |
} | |
} | |
if (args.length != expectedNum) | |
{ | |
System.err.println("Invalid number of arguments."); | |
callUsage(mainClass); | |
System.exit(1); | |
} | |
} | |
/** | |
* Checks the range of an integer. Prints to standard | |
* error and exits with code 1 on failure. | |
* | |
* @param val value to check | |
* @param low lowest allowed value (= inclusive) | |
* @param high highest allowed value (= inclusive) | |
* @param paramName parameter name | |
*/ | |
protected static void checkRange(long val, long low, long high, String paramName) | |
{ | |
if (val < low || val > high) | |
{ | |
System.err.println(String.format("Parameter %s must lie between %d and %d.", paramName, low, high)); | |
System.exit(1); | |
} | |
} | |
/** | |
* Combines the functionality of {@literal toInt} and {@literal checkRange}. | |
* @param s string to convert | |
* @param low lowest allowed value (= inclusive) | |
* @param high highest allowed value (= inclusive) | |
* @param paramName parameter name | |
* @return {@literal s} converted to string | |
*/ | |
protected static int toIntInRange(String s, int low, int high, String paramName) | |
{ | |
long ret = toLong(s, paramName); | |
checkRange(ret, low, high, paramName); | |
return (int)ret; | |
} | |
/** | |
* Call usage() on the actual main class. Slight trickery to get around | |
* Java's lack of static method overriding. | |
* | |
* @param mainClass The actual main class of the program. | |
*/ | |
private static void callUsage(Class<?> mainClass) | |
{ | |
try | |
{ | |
Method usageMethod = mainClass.getMethod("usage"); | |
usageMethod.invoke(null); | |
} | |
catch (Exception e) | |
{ | |
defaultUsage(); | |
} | |
} | |
/** | |
* Prints program usage information to standard error. | |
*/ | |
private static void defaultUsage() | |
{ | |
System.err.println("Uh-oh. This class doesn't specify usage information."); | |
} | |
/** | |
* Converts a parameter string to a long. Prints to | |
* standard error and exits with code 1 on failure. | |
* | |
* @param s string value | |
* @param paramName parameter name | |
* @return {@literal s} converted to string. | |
*/ | |
protected static long toLong(String s, String paramName) | |
{ | |
try | |
{ | |
return Long.parseLong(s); | |
} | |
catch (NumberFormatException nfe) | |
{ | |
System.err.println(String.format("Parameter %s must be an integer.", paramName)); | |
System.exit(1); | |
return -1; | |
} | |
} | |
protected static void commandLineLoop(GracefullyExitable primaryTask, Class<?> mainClass) | |
{ | |
BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); | |
while (true) | |
{ | |
String line; | |
// FIXME: is a TTY? | |
System.out.print("> "); | |
System.out.flush(); | |
try | |
{ | |
line = br.readLine(); | |
} | |
catch (EOFException eofe) | |
{ | |
// assume user wants to terminate gracefully | |
if (primaryTask != null) | |
primaryTask.pleaseStop(); | |
return; | |
} | |
catch (IOException ioe) | |
{ | |
System.err.println("Error reading from standard input: " + ioe.toString()); | |
continue; | |
} | |
if (line == null) | |
{ | |
// EOF; assume user wants to terminate gracefully | |
if (primaryTask != null) | |
primaryTask.pleaseStop(); | |
return; | |
} | |
Method pc; | |
try | |
{ | |
pc = mainClass.getMethod("processCommand", String.class); | |
} | |
catch (NoSuchMethodException nsme) | |
{ | |
System.err.println(String.format("Error: %s must implement public static boolean processCommand(String cmd).", mainClass)); | |
if (primaryTask != null) | |
primaryTask.pleaseStop(); | |
return; | |
} | |
// trim bounding spaces away | |
line = line.trim(); | |
Boolean ret = Boolean.FALSE; | |
try | |
{ | |
ret = (Boolean)pc.invoke(null, line); | |
} | |
catch (InvocationTargetException ite) | |
{ | |
Throwable te = ite.getTargetException(); | |
System.err.println("processCommand failed: " + te.toString()); | |
te.printStackTrace(System.err); | |
} | |
catch (Exception e) | |
{ | |
System.err.println("Error invoking processCommand: " + e.toString()); | |
} | |
if (!ret.booleanValue()) | |
{ | |
// processCommand returned "false"; stop | |
if (primaryTask != null) | |
primaryTask.pleaseStop(); | |
return; | |
} | |
} | |
} | |
/** | |
* Fetches the private key from the given file. | |
* @param filename the file containing the private key | |
* @return the JCA-compatible private key | |
*/ | |
public static PrivateKey getPrivateKey(String filename) | |
{ | |
FileReader frdr; | |
PEMReader rdr; | |
try | |
{ | |
frdr = new FileReader(filename); | |
} | |
catch (FileNotFoundException fnfe) | |
{ | |
l.error("Private key file not found.", fnfe); | |
System.exit(2); | |
return null; | |
} | |
rdr = new PEMReader(frdr, new PasswordFinder() { | |
@Override | |
public char[] getPassword() | |
{ | |
System.out.print("Enter private key pass phrase: "); | |
System.out.flush(); | |
try | |
{ | |
return new BufferedReader(new InputStreamReader(System.in)).readLine().toCharArray(); | |
} | |
catch (IOException ex) | |
{ | |
l.error("Error reading private key pass phrase.", ex); | |
return new char[0]; | |
} | |
} | |
}); | |
KeyPair keys; | |
try | |
{ | |
keys = (KeyPair)rdr.readObject(); | |
} | |
catch (IOException ioe) | |
{ | |
l.error("Error reading private key.", ioe); | |
System.exit(2); | |
return null; | |
} | |
return keys.getPrivate(); | |
} | |
/** | |
* Fetches the public key from the given file. | |
* @param filename the file containing the public key | |
* @return the JCA-compatible public key | |
*/ | |
public static PublicKey getPublicKey(String filename) | |
{ | |
FileReader frdr; | |
PEMReader rdr; | |
try | |
{ | |
frdr = new FileReader(filename); | |
} | |
catch (FileNotFoundException fnfe) | |
{ | |
l.error("Public key file not found.", fnfe); | |
System.exit(2); | |
return null; | |
} | |
rdr = new PEMReader(frdr); | |
PublicKey ret; | |
try | |
{ | |
ret = (PublicKey)rdr.readObject(); | |
} | |
catch (IOException ioe) | |
{ | |
l.error("Error reading public key.", ioe); | |
System.exit(2); | |
return null; | |
} | |
return ret; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment