001: /*
002: * This is free software, licensed under the Gnu Public License (GPL)
003: * get a copy from <http://www.gnu.org/licenses/gpl.html>
004: * $Id: DriverCommand.java,v 1.14 2005/11/27 16:20:28 hzeller Exp $
005: * author: Henner Zeller <H.Zeller@acm.org>
006: */
007: package henplus.commands;
008:
009: import henplus.AbstractCommand;
010: import henplus.CommandDispatcher;
011: import henplus.HenPlus;
012: import henplus.SQLSession;
013: import henplus.io.ConfigurationContainer;
014: import henplus.view.Column;
015: import henplus.view.ColumnMetaData;
016: import henplus.view.TableRenderer;
017: import henplus.view.util.SortedMatchIterator;
018:
019: import java.sql.Driver;
020: import java.util.HashMap;
021: import java.util.Iterator;
022: import java.util.Map;
023: import java.util.SortedMap;
024: import java.util.StringTokenizer;
025: import java.util.TreeMap;
026:
027: /**
028: * document me.
029: */
030: public final class DriverCommand extends AbstractCommand {
031: private final static boolean verbose = false; // debug.
032: private final static String[][] KNOWN_DRIVERS = {
033: { "Oracle", "oracle.jdbc.driver.OracleDriver",
034: "jdbc:oracle:thin:@localhost:1521:ORCL" },
035: { "DB2", "COM.ibm.db2.jdbc.net.DB2Driver",
036: "jdbc:db2://localhost:6789/foobar" },
037: { "Postgres", "org.postgresql.Driver",
038: "jdbc:postgresql://localhost/foobar" },
039: { "SAP-DB", "com.sap.dbtech.jdbc.DriverSapDB",
040: "jdbc:sapdb://localhost/foobar" },
041: { "MySQL", "org.gjt.mm.mysql.Driver",
042: "jdbc:mysql://localhost/foobar" },
043: { "Adabas", "de.sag.jdbc.adabasd.ADriver",
044: "jdbc:adabasd://localhost:7200/work" } };
045:
046: private final static String DRIVERS_FILENAME = "drivers";
047: private final static ColumnMetaData[] DRV_META;
048: static {
049: DRV_META = new ColumnMetaData[4];
050: DRV_META[0] = new ColumnMetaData("for");
051: DRV_META[1] = new ColumnMetaData("driver class");
052: DRV_META[2] = new ColumnMetaData("Version");
053: DRV_META[3] = new ColumnMetaData("sample url");
054: }
055:
056: private final static class DriverDescription {
057: private final String className;
058: private final String sampleURL;
059:
060: private String version; // known after loading.
061: private boolean loaded;
062:
063: public DriverDescription(String cn, String surl) {
064: className = cn;
065: sampleURL = surl;
066: load();
067: }
068:
069: public String getClassName() {
070: return className;
071: }
072:
073: public String getSampleURL() {
074: return sampleURL;
075: }
076:
077: public String getVersion() {
078: return version;
079: }
080:
081: public boolean isLoaded() {
082: return loaded;
083: }
084:
085: public boolean load() {
086: try {
087: if (verbose)
088: HenPlus.msg().print(
089: "loading .. '" + className + "'");
090: Class cls = Class.forName(className);
091: if (verbose)
092: HenPlus.msg().println(" done.");
093: try {
094: Driver driver = (Driver) cls.newInstance();
095: version = (driver.getMajorVersion() + "." + driver
096: .getMinorVersion());
097: } catch (Throwable t) {
098: // ign.
099: }
100: loaded = true;
101: } catch (Throwable t) {
102: if (verbose)
103: HenPlus.msg().println(" failed: " + t.getMessage());
104: loaded = false;
105: }
106: return loaded;
107: }
108: }
109:
110: private final SortedMap/*<String,DriverDescription>*/_drivers;
111: private final ConfigurationContainer _config;
112:
113: /**
114: * returns the command-strings this command can handle.
115: */
116: public String[] getCommandList() {
117: return new String[] { "list-drivers", "register", "unregister" };
118: }
119:
120: public DriverCommand(HenPlus henplus) {
121: _drivers = new TreeMap();
122: _config = henplus
123: .createConfigurationContainer(DRIVERS_FILENAME);
124: Map props = _config.readProperties();
125: final Iterator propNames = props.keySet().iterator();
126: while (propNames.hasNext()) {
127: final String name = (String) propNames.next();
128: if (name.startsWith("driver.") && name.endsWith(".class")) {
129: String databaseName = name.substring(
130: "driver.".length(), name.length()
131: - ".class".length());
132: String exampleName = "driver." + databaseName
133: + ".example";
134: DriverDescription desc;
135:
136: desc = new DriverDescription((String) props.get(name),
137: (String) props.get(exampleName));
138: _drivers.put(databaseName, desc);
139: }
140: }
141: if (_drivers.size() == 0) {
142: for (int i = 0; i < KNOWN_DRIVERS.length; ++i) {
143: String[] row = KNOWN_DRIVERS[i];
144: _drivers.put(row[0], new DriverDescription(row[1],
145: row[2]));
146: }
147: }
148: }
149:
150: public boolean requiresValidSession(String cmd) {
151: return false;
152: }
153:
154: /**
155: * execute the command given.
156: */
157: public int execute(SQLSession currentSession, String cmd,
158: String param) {
159: StringTokenizer st = new StringTokenizer(param);
160: int argc = st.countTokens();
161:
162: if ("list-drivers".equals(cmd)) {
163: if (argc == 0) {
164: HenPlus
165: .msg()
166: .println(
167: "loaded drivers are marked with '*' (otherwise not found in CLASSPATH)");
168: DRV_META[0].resetWidth();
169: DRV_META[1].resetWidth();
170: DRV_META[2].resetWidth();
171: DRV_META[3].resetWidth();
172: TableRenderer table = new TableRenderer(DRV_META,
173: HenPlus.out());
174: Iterator vars = _drivers.entrySet().iterator();
175: while (vars.hasNext()) {
176: Map.Entry entry = (Map.Entry) vars.next();
177: Column[] row = new Column[4];
178: DriverDescription desc = (DriverDescription) entry
179: .getValue();
180: String dbName = (String) entry.getKey();
181: row[0] = new Column(((desc.isLoaded()) ? "* "
182: : " ")
183: + dbName);
184: row[1] = new Column(desc.getClassName());
185: row[2] = new Column(desc.getVersion());
186: row[3] = new Column(desc.getSampleURL());
187: table.addRow(row);
188: }
189: table.closeTable();
190: return SUCCESS;
191: } else
192: return SYNTAX_ERROR;
193: } else if ("register".equals(cmd)) {
194: if (argc < 2 || argc > 3)
195: return SYNTAX_ERROR;
196: String shortname = (String) st.nextElement();
197: String driverClass = (String) st.nextElement();
198: String sampleURL = null;
199: if (argc >= 3) {
200: sampleURL = (String) st.nextElement();
201: }
202: DriverDescription drv;
203: drv = new DriverDescription(driverClass, sampleURL);
204: if (!drv.isLoaded()) {
205: HenPlus.msg().println(
206: "cannot load driver class '" + driverClass
207: + "'");
208: return EXEC_FAILED;
209: } else {
210: _drivers.put(shortname, drv);
211: }
212: } else if ("unregister".equals(cmd)) {
213: if (argc != 1)
214: return SYNTAX_ERROR;
215: String shortname = (String) st.nextElement();
216: if (!_drivers.containsKey(shortname)) {
217: HenPlus.msg().println(
218: "unknown driver for '" + shortname + "'");
219: return EXEC_FAILED;
220: } else {
221: _drivers.remove(shortname);
222: }
223: }
224: return SUCCESS;
225: }
226:
227: public Iterator complete(CommandDispatcher disp,
228: String partialCommand, final String lastWord) {
229: StringTokenizer st = new StringTokenizer(partialCommand);
230: String cmd = (String) st.nextElement();
231: int argc = st.countTokens();
232: // list-drivers gets no names.
233: if ("list-drivers".equals(cmd))
234: return null;
235: // do not complete beyond first word.
236: if (argc > ("".equals(lastWord) ? 0 : 1)) {
237: return null;
238: }
239: return new SortedMatchIterator(lastWord, _drivers);
240: }
241:
242: public void shutdown() {
243: Map result = new HashMap();
244: Iterator drvs = _drivers.entrySet().iterator();
245: while (drvs.hasNext()) {
246: Map.Entry entry = (Map.Entry) drvs.next();
247: String shortName = (String) entry.getKey();
248: DriverDescription desc = (DriverDescription) entry
249: .getValue();
250: result.put("driver." + shortName + ".class", desc
251: .getClassName());
252: result.put("driver." + shortName + ".example", desc
253: .getSampleURL());
254: }
255: _config.storeProperties(result, true, "JDBC drivers");
256: }
257:
258: /**
259: * return a descriptive string.
260: */
261: public String getShortDescription() {
262: return "handle JDBC drivers";
263: }
264:
265: public String getSynopsis(String cmd) {
266: if ("unregister".equals(cmd)) {
267: return cmd + " <shortname>";
268: } else if ("register".equals(cmd)) {
269: return cmd + " <shortname> <driver-class> [sample-url]";
270: }
271: return cmd;
272: }
273:
274: public String getLongDescription(String cmd) {
275: String dsc = null;
276: if ("register".equals(cmd)) {
277: dsc = "\tRegister a new driver. Basically this adds the JDBC\n"
278: + "\tdriver represented by its driver class. You have to give\n"
279: + "\ta short name, that is used in the user interface. You\n"
280: + "\tmight give a sample JDBC-URL that is shown with the\n"
281: + "\tlist-drivers command. This command tries to load the\n"
282: + "\tdriver from the CLASSPATH; if it is not found, then it\n"
283: + "\tis not added to the list of usable drivers.";
284: } else if ("unregister".equals(cmd)) {
285: dsc = "\tUnregister the driver with the given shortname. There\n"
286: + "\tis a command line completion for the shortname, but you\n"
287: + "\tcan list them as well with the list-drivers command.";
288: } else if ("list-drivers".equals(cmd)) {
289: dsc = "\tList the drivers that are registered. The drivers, that\n"
290: + "\tare actually loaded have a little star (*) in the first\n"
291: + "\tcolumn. If it is not loaded, than you have to augment your\n"
292: + "\tCLASSPATH in order to be able to connect to some database\n"
293: + "\tof that kind.";
294: }
295: return dsc;
296: }
297: }
298:
299: /*
300: * Local variables:
301: * c-basic-offset: 4
302: * compile-command: "ant -emacs -find build.xml"
303: * End:
304: */
|