package winstone.cmdline; import winstone.Launcher; import winstone.realm.ArgumentsRealm; import java.io.File; import java.lang.reflect.Field; import java.lang.reflect.Modifier; import java.util.ArrayList; import java.util.List; import java.util.Map; /** * Command line options used in {@link Launcher}. * * @author Kohsuke Kawaguchi */ public class Option<T> { /** * List up all the known options. */ public static List<Option<?>> all(Class<?> clazz) { List<Option<?>> r = new ArrayList<Option<?>>(); for (Field f : clazz.getFields()) { if (Modifier.isStatic(f.getModifiers()) && Option.class.isAssignableFrom(f.getType())) { try { r.add((Option<?>) f.get(null)); } catch (IllegalAccessException e) { throw (Error)new IllegalAccessError().initCause(e); } } } return r; } public static final OFile WEBROOT=file("webroot"); public static final OFile WARFILE=file("warfile"); public static final OFile WEBAPPS_DIR=file("webappsDir"); public static final OFile JAVA_HOME=file("javaHome"); public static final OFile TOOLS_JAR=file("toolsJar"); public static final OFile CONFIG=file("config"); public static final OString PREFIX=string("prefix",""); public static final OFile COMMON_LIB_FOLDER=file("commonLibFolder"); public static final OBoolean LOG_THROWING_LINE_NO=bool("logThrowingLineNo",false); public static final OBoolean LOG_THROWING_THREAD=bool("logThrowingThread",false); public static final OBoolean DEBUG=bool("debug",false); // these are combined with protocol to form options public static final OInt _PORT = integer("Port"); public static final OString _LISTEN_ADDRESS = string("ListenAddress"); /** * Number of milliseconds for the HTTP keep-alive to hang around until the next request is sent. */ public static final OInt _KEEP_ALIVE_TIMEOUT = integer("KeepAliveTimeout",5000); public static final OInt HTTP_PORT=integer("http"+_PORT,8080); public static final OString HTTP_LISTEN_ADDRESS=string("http"+ _LISTEN_ADDRESS); public static final OInt HTTP_KEEP_ALIVE_TIMEOUT=integer("http" + _KEEP_ALIVE_TIMEOUT, _KEEP_ALIVE_TIMEOUT.defaultValue); public static final OInt HTTPS_PORT=integer("https"+_PORT,-1); public static final OString HTTPS_LISTEN_ADDRESS=string("https"+_LISTEN_ADDRESS); public static final OInt HTTPS_KEEP_ALIVE_TIMEOUT=integer("https" + _KEEP_ALIVE_TIMEOUT, _KEEP_ALIVE_TIMEOUT.defaultValue); public static final OFile HTTPS_KEY_STORE=file("httpsKeyStore"); public static final OString HTTPS_KEY_STORE_PASSWORD=string("httpsKeyStorePassword"); public static final OString HTTPS_PRIVATE_KEY_PASSWORD=string("httpsPrivateKeyPassword"); public static final OString HTTPS_KEY_MANAGER_TYPE=string("httpsKeyManagerType","SunX509"); public static final OBoolean HTTPS_VERIFY_CLIENT=bool("httpsVerifyClient",false); public static final OFile HTTPS_CERTIFICATE=file("httpsCertificate"); public static final OString HTTPS_CERTIFICATE_ALIAS=string("httpsCertificateAlias"); public static final OFile HTTPS_PRIVATE_KEY=file("httpsPrivateKey"); public static final OInt AJP13_PORT=integer("ajp13"+_PORT,-1); public static final OString AJP13_LISTEN_ADDRESS=string("ajp13"+_LISTEN_ADDRESS); public static final OInt CONTROL_PORT=integer("controlPort",-1); /** * How many requests do we handle concurrently? * * If the system gets really loaded, too many concurrent threads will create vicious cycles * and make everyone slow (or worst case choke every request by OOME), so better to err * on the conservative side (and have inbound connections wait in the queue) */ public static final OInt HANDLER_COUNT_MAX =integer("handlerCountMax",40); /** * Leave this number of request handler threads in the pool even when they are idle. * Other threads are destroyed when they are idle to free up resources. */ public static final OInt HANDLER_COUNT_MAX_IDLE=integer("handlerCountMaxIdle",5); public static final OBoolean USE_JASPER=bool("useJasper",false); public static final OString MIME_TYPES=string("mimeTypes"); public static final OInt MAX_PARAM_COUNT=integer("maxParamCount",-1); public static final OBoolean USAGE=bool("usage",false); public static final OInt SESSION_TIMEOUT=integer("sessionTimeout",-1); public static final OInt REQUEST_HEADER_SIZE=integer("requestHeaderSize",8192); // default for jetty 9 public static final OInt REQUEST_FORM_CONTENT_SIZE=integer("requestFormContentSize",-1); // no limit (compat with old winstone) public static final OBoolean HELP=bool("help",false); public static final OClass REALM_CLASS_NAME=clazz("realmClassName", ArgumentsRealm.class); public static final OString ARGUMENTS_REALM_PASSWORD=string("argumentsRealm.passwd."); public static final OString ARGUMENTS_REALM_ROLES=string("argumentsRealm.roles."); public static final OFile FILEREALM_CONFIGFILE=file("fileRealm.configFile"); public static final OClass ACCESS_LOGGER_CLASSNAME=clazz("accessLoggerClassName",null); public static final OString SIMPLE_ACCESS_LOGGER_FORMAT=string("simpleAccessLogger.format","combined"); public static final OString SIMPLE_ACCESS_LOGGER_FILE=string("simpleAccessLogger.file","logs/###host###/###webapp###_access.log"); /** * Option name without the "--" prefix. */ public final String name; /** * Expected type. */ public final Class<T> type; public final T defaultValue; public Option(String name, Class<T> type, T defaultValue) { this.name = name; this.type = type; this.defaultValue = defaultValue; } public void remove(Map args) { args.remove(name); } public void put(Map args, String value) { args.put(name, value); } public boolean isIn(Map args) { return args.containsKey(name); } /** * Indicates an option name that takes some argument. */ public boolean isWildcard() { return name.endsWith("."); } @Override public String toString() { return name; } public static OString string(String name) { return new OString(name,null); } public static OString string(String name, String defaultValue) { return new OString(name,defaultValue); } public static OBoolean bool(String name, boolean defaultValue) { return new OBoolean(name,defaultValue); } public static OFile file(String name) { return new OFile(name); } public static OClass clazz(String name, Class defaultValue) { return new OClass(name,defaultValue); } public static OInt integer(String name) { return new OInt(name,-1); } public static OInt integer(String name,int defaultValue) { return new OInt(name,defaultValue); } public static class OBoolean extends Option<Boolean> { public OBoolean(String name, boolean defaultValue) { super(name, Boolean.class, defaultValue); } public boolean get(Map args) { return get(args,defaultValue); } public boolean get(Map args, boolean defaultValue) { return booleanArg(args, name, defaultValue); } } public static class OInt extends Option<Integer> { public OInt(String name, int defaultValue) { super(name, Integer.class, defaultValue); } public int get(Map args) { return intArg(args, name, defaultValue); } public int get(Map args, int defaultValue) { return intArg(args, name, defaultValue); } } public static class OString extends Option<String> { public OString(String name, String defaultValue) { super(name, String.class, defaultValue); } public String get(Map args) { return get(args,defaultValue); } public char[] getCharArray(Map args) { String v = get(args); return v!=null ? v.toCharArray() : null; } public String get(Map args, String defaultValue) { String v = (String)args.get(name); return v!=null ? v : defaultValue; } } public static class OFile extends Option<File> { public OFile(String name) { super(name, File.class,null); } public File get(Map args, File defaultValue) { String v = (String)args.get(name); return v!=null ? new File(v) : defaultValue; } public File get(Map args) { return get(args,null); } } public static class OClass extends Option<Class> { public OClass(String name,Class defaultValue) { super(name, Class.class, defaultValue); } public <T> Class<? extends T> get(Map args, Class<T> expectedType) throws ClassNotFoundException { return get(args,expectedType,getClass().getClassLoader()); } public <T> Class<? extends T> get(Map args, Class<T> expectedType, ClassLoader cl) throws ClassNotFoundException { String v = (String)args.get(name); if (v==null) return defaultValue; v=v.trim(); if (v.length()==0) return defaultValue; Class<?> c = Class.forName(v, true, cl); if (!expectedType.isAssignableFrom(c)) throw new ClassNotFoundException("Expected a subype of "+expectedType+" but got "+c+" instead"); return c.asSubclass(expectedType); } } // static { // String[] protocols = {"http","https","ajp13"}; // for (int i=0; i<protocols.length; i++) { // String protocol = protocols[i]; // String[] // } // } public static boolean booleanArg(Map args, String name, boolean defaultTrue) { String value = (String) args.get(name); if (defaultTrue) return (value == null) || (value.equalsIgnoreCase("true") || value.equalsIgnoreCase("yes")); else return (value != null) && (value.equalsIgnoreCase("true") || value.equalsIgnoreCase("yes")); } public static String stringArg(Map args, String name, String defaultValue) { return (String) (args.get(name) == null ? defaultValue : args.get(name)); } public static int intArg(Map args, String name, int defaultValue) { return Integer.parseInt(stringArg(args, name, "" + defaultValue)); } }