Source Code Cross Referenced for SQLShell.java in  » Database-Client » sqlshell » nl » improved » sqlclient » Java Source Code / Java DocumentationJava Source Code and Java Documentation

Java Source Code / Java Documentation
1. 6.0 JDK Core
2. 6.0 JDK Modules
3. 6.0 JDK Modules com.sun
4. 6.0 JDK Modules com.sun.java
5. 6.0 JDK Modules sun
6. 6.0 JDK Platform
7. Ajax
8. Apache Harmony Java SE
9. Aspect oriented
10. Authentication Authorization
11. Blogger System
12. Build
13. Byte Code
14. Cache
15. Chart
16. Chat
17. Code Analyzer
18. Collaboration
19. Content Management System
20. Database Client
21. Database DBMS
22. Database JDBC Connection Pool
23. Database ORM
24. Development
25. EJB Server geronimo
26. EJB Server GlassFish
27. EJB Server JBoss 4.2.1
28. EJB Server resin 3.1.5
29. ERP CRM Financial
30. ESB
31. Forum
32. GIS
33. Graphic Library
34. Groupware
35. HTML Parser
36. IDE
37. IDE Eclipse
38. IDE Netbeans
39. Installer
40. Internationalization Localization
41. Inversion of Control
42. Issue Tracking
43. J2EE
44. JBoss
45. JMS
46. JMX
47. Library
48. Mail Clients
49. Net
50. Parser
51. PDF
52. Portal
53. Profiler
54. Project Management
55. Report
56. RSS RDF
57. Rule Engine
58. Science
59. Scripting
60. Search Engine
61. Security
62. Sevlet Container
63. Source Control
64. Swing Library
65. Template Engine
66. Test Coverage
67. Testing
68. UML
69. Web Crawler
70. Web Framework
71. Web Mail
72. Web Server
73. Web Services
74. Web Services apache cxf 2.0.1
75. Web Services AXIS2
76. Wiki Engine
77. Workflow Engines
78. XML
79. XML UI
Java
Java Tutorial
Java Open Source
Jar File Download
Java Articles
Java Products
Java by API
Photoshop Tutorials
Maya Tutorials
Flash Tutorials
3ds-Max Tutorials
Illustrator Tutorials
GIMP Tutorials
C# / C Sharp
C# / CSharp Tutorial
C# / CSharp Open Source
ASP.Net
ASP.NET Tutorial
JavaScript DHTML
JavaScript Tutorial
JavaScript Reference
HTML / CSS
HTML CSS Reference
C / ANSI-C
C Tutorial
C++
C++ Tutorial
Ruby
PHP
Python
Python Tutorial
Python Open Source
SQL Server / T-SQL
SQL Server / T-SQL Tutorial
Oracle PL / SQL
Oracle PL/SQL Tutorial
PostgreSQL
SQL / MySQL
MySQL Tutorial
VB.Net
VB.Net Tutorial
Flash / Flex / ActionScript
VBA / Excel / Access / Word
XML
XML Tutorial
Microsoft Office PowerPoint 2007 Tutorial
Microsoft Office Excel 2007 Tutorial
Microsoft Office Word 2007 Tutorial
Java Source Code / Java Documentation » Database Client » sqlshell » nl.improved.sqlclient 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


0001:        /*
0002:         * Copyright 2007 Roy van der Kuil (roy@vanderkuil.nl) and Stefan Rotman (stefan@rotman.net)
0003:         *
0004:         * Licensed under the Apache License, Version 2.0 (the "License");
0005:         * you may not use this file except in compliance with the License.
0006:         * You may obtain a copy of the License at
0007:         *
0008:         *     http://www.apache.org/licenses/LICENSE-2.0
0009:         *
0010:         * Unless required by applicable law or agreed to in writing, software
0011:         * distributed under the License is distributed on an "AS IS" BASIS,
0012:         * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
0013:         * See the License for the specific language governing permissions and
0014:         * limitations under the License.
0015:         */
0016:        package nl.improved.sqlclient;
0017:
0018:        import java.io.*;
0019:        import java.sql.Connection;
0020:        import java.sql.ResultSet;
0021:        import java.sql.SQLException;
0022:        import java.util.Arrays;
0023:        import java.util.ArrayList;
0024:        import java.util.Iterator;
0025:        import java.util.List;
0026:        import java.util.Map;
0027:        import java.util.LinkedHashMap;
0028:        import java.util.logging.Level;
0029:        import java.util.logging.Logger;
0030:        import jcurses.widgets.Window;
0031:        import jcurses.system.InputChar;
0032:        import jcurses.system.Toolkit;
0033:        import jcurses.system.CharColor;
0034:        import jcurses.widgets.PopUpMenu;
0035:        import nl.improved.sqlclient.commands.*;
0036:
0037:        /**
0038:         * The SQLShell main class.
0039:         * This class provides a (textbased) window for entering sql commands.
0040:         */
0041:        public class SQLShell extends Window {
0042:
0043:            /**
0044:             * The current command thread executing a SQLShell command.
0045:             */
0046:            private CommandThread commandThread;
0047:            /**
0048:             * True when the prompt should be visible.
0049:             * Normally it is not visible during the execution of a command
0050:             */
0051:            private boolean showPrompt = true;
0052:
0053:            /**
0054:             * The (default) maximum matches to show in a selection dialog.
0055:             */
0056:            private static final int MAX_MATCH_SIZE = 15;
0057:            private int MAX_LINE_LENGTH; // not static and final.. since it can change on window resize
0058:
0059:            /**
0060:             * Page up count 0 means were at the bottom of our screen.
0061:             * Increasement of the pageup count moves the visible part of the screen up.
0062:             */
0063:            private int pageUpCount = 0;
0064:            /**
0065:             * All lines in a screen.
0066:             */
0067:            private List<CharSequence> screenBuffer = new LimitedArrayList<CharSequence>(
0068:                    1000);
0069:            /**
0070:             * The current command lines.
0071:             */
0072:            private SQLCommand commandLines;
0073:            /**
0074:             * All commands in history.
0075:             */
0076:            private List<SQLCommand> commandHistory = new LimitedArrayList<SQLCommand>(
0077:                    50);
0078:            /**
0079:             * Index for browsing commands.
0080:             */
0081:            private int commandIndex = 0;
0082:            /**
0083:             * An empty line for easy line completion (fill with spaces).
0084:             */
0085:            private String emptyLine;
0086:            /**
0087:             * The cursor position in the command lines list.
0088:             * 0,0 means it is at the first line at the first character
0089:             * 10,5 means it is at the 11th character at the 6th line
0090:             */
0091:            private Point cursorPosition = new Point(0, 0);
0092:            /**
0093:             * The prompt to show when entering sql commands.
0094:             */
0095:            private static final String PROMPT = "SQL";
0096:            /**
0097:             * Some debug info holding the last trace of an exception.
0098:             */
0099:            private String lastExceptionDetails;
0100:
0101:            /**
0102:             * The output file when spool is on.
0103:             */
0104:            private Writer spoolWriter;
0105:            /**
0106:             * A manager for available commands.
0107:             */
0108:            private CommandManager commands = new CommandManager();
0109:
0110:            /**
0111:             * A map of string key representation to a action that should be executed when a specific key is pressed.
0112:             */
0113:            private Map<String, KeyAction> actionKeys = new LinkedHashMap<String, KeyAction>();
0114:
0115:            /**
0116:             * Constructor.
0117:             */
0118:            public SQLShell() {
0119:                super (Toolkit.getScreenWidth(), Toolkit.getScreenHeight(),
0120:                        true, "SQLShell");
0121:                char[] emptyLineChar = new char[Toolkit.getScreenWidth()];
0122:                Arrays.fill(emptyLineChar, ' ');
0123:                emptyLine = new String(emptyLineChar);
0124:
0125:                // initialize the command shell
0126:                commandLines = new SQLCommand();
0127:                commandHistory.add(commandLines);
0128:                newLine();
0129:
0130:                // Register all known commands
0131:                commands.register("CONNECT[\\s]*.*", new ConnectCommand());
0132:                commands.register("DISCONNECT[\\s]*", new DisConnectCommand());
0133:                commands
0134:                        .register(
0135:                                "SHOW[\\s]+[A-Z]+(|[A-Z]|_|\\.)*(|[\\s]+HAVING[\\s][A-Z]*.*)",
0136:                                new ShowCommand());
0137:                commands.register("DESC[\\s]+[A-Z]+(|[A-Z]|_|\\.)*",
0138:                        new DescCommand());
0139:                commands.register("WINDOW[\\s]+[A-Z]+", new WindowCommand());
0140:                commands.register("INFO[\\s]*", new InfoCommand());
0141:                commands.register("HELP[\\s]*.*", new HelpCommand());
0142:                commands.register("HISTORY[\\s]*.*", new HistoryCommand());
0143:                commands.register("SPOOL[\\s]*.*", new SpoolCommand());
0144:                commands.register("QUIT[\\s]*", new QuitCommand("quit"));
0145:                commands.register("EXIT[\\s]*", new QuitCommand("exit"));
0146:                //commands.register("\\\\Q[\\s]*", new QuitCommand("\\q"));
0147:                commands.register("@.*", new ExecuteBatchCommand());
0148:                commands.register(
0149:                        "(SELECT|UPDATE|ALTER|INSERT|DELETE).*;[\\s]*",
0150:                        new QueryCommand());
0151:
0152:                // keys
0153:                actionKeys.put(Integer.toString(InputChar.KEY_LEFT),
0154:                        new KeyAction() {
0155:                            public void execute() {
0156:                                if (cursorPosition.x > 0) {
0157:                                    cursorPosition.x--;
0158:                                } else if (cursorPosition.y > 0) {
0159:                                    cursorPosition.y--;
0160:                                    cursorPosition.x = commandLines.getLines()
0161:                                            .get(cursorPosition.y).length();
0162:                                }
0163:                            }
0164:
0165:                            public CharSequence getHelp() {
0166:                                return "Arrow Left:\tMove cursor to the left";
0167:                            }
0168:                        });
0169:                actionKeys.put(Integer.toString(InputChar.KEY_RIGHT),
0170:                        new KeyAction() {
0171:                            public void execute() {
0172:                                CharSequence tmp = commandLines.getLines().get(
0173:                                        cursorPosition.y);
0174:                                if (cursorPosition.x < tmp.length()) {
0175:                                    cursorPosition.x++;
0176:                                } else if (cursorPosition.y < commandLines
0177:                                        .getLines().size() - 1) {
0178:                                    cursorPosition.x = 0;
0179:                                    cursorPosition.y++;
0180:                                }
0181:                            }
0182:
0183:                            public CharSequence getHelp() {
0184:                                return "Arrow Right:\tMove cursor to the right";
0185:                            }
0186:                        });
0187:                actionKeys.put(Integer.toString(InputChar.KEY_UP),
0188:                        new KeyAction() {
0189:                            public void execute() {
0190:                                if (commandIndex > 0) {
0191:                                    commandLines = commandHistory
0192:                                            .get(--commandIndex);
0193:                                    cursorPosition.y = commandLines.getLines()
0194:                                            .size() - 1;
0195:                                    CharSequence lineBuffer = commandLines
0196:                                            .getLines().get(cursorPosition.y);
0197:                                    cursorPosition.x = lineBuffer.length();
0198:                                }
0199:                            }
0200:
0201:                            public CharSequence getHelp() {
0202:                                return "Arrow Up:\tBrowse to previous command in the history";
0203:                            }
0204:                        });
0205:                actionKeys.put(Integer.toString(InputChar.KEY_DOWN),
0206:                        new KeyAction() {
0207:                            public void execute() {
0208:                                if (commandIndex < commandHistory.size() - 1) {
0209:                                    commandLines = commandHistory
0210:                                            .get(++commandIndex);
0211:                                    cursorPosition.y = commandLines.getLines()
0212:                                            .size() - 1;
0213:                                    CharSequence lineBuffer = commandLines
0214:                                            .getLines().get(cursorPosition.y);
0215:                                    cursorPosition.x = lineBuffer.length();
0216:                                }
0217:                            }
0218:
0219:                            public CharSequence getHelp() {
0220:                                return "Arrow Down:\tBrowse to next command in the history";
0221:                            }
0222:                        });
0223:                actionKeys.put(Integer.toString(InputChar.KEY_END),
0224:                        new KeyAction() {
0225:                            public void execute() {
0226:                                int curLineEnd = commandLines.getLines().get(
0227:                                        cursorPosition.y).length();
0228:                                if (cursorPosition.x == curLineEnd) {
0229:                                    cursorPosition.y = commandLines.getLines()
0230:                                            .size() - 1;
0231:                                    CharSequence lineBuffer = commandLines
0232:                                            .getLines().get(cursorPosition.y);
0233:                                    cursorPosition.x = lineBuffer.length();
0234:                                } else {
0235:                                    cursorPosition.x = curLineEnd;
0236:                                }
0237:                            }
0238:
0239:                            public CharSequence getHelp() {
0240:                                return "End:\tMove the cursor to the end of the line, of if already there to the end of the command";
0241:                            }
0242:                        });
0243:                actionKeys.put(Integer.toString(InputChar.KEY_HOME),
0244:                        new KeyAction() {
0245:                            public void execute() {
0246:                                if (cursorPosition.x == 0) {
0247:                                    cursorPosition.y = 0;
0248:                                }
0249:                                cursorPosition.x = 0;
0250:                            }
0251:
0252:                            public CharSequence getHelp() {
0253:                                return "Home:\tMove the cursor to the start of the line, of if already there to the start of the command";
0254:                            }
0255:                        });
0256:                actionKeys.put(Integer.toString(InputChar.KEY_BACKSPACE),
0257:                        new KeyAction() {
0258:                            public void execute() {
0259:                                if (cursorPosition.x == 0) {
0260:                                    if (cursorPosition.y > 0) {
0261:                                        StringBuilder line = getEditableCommand()
0262:                                                .getEditableLines().remove(
0263:                                                        cursorPosition.y);
0264:                                        cursorPosition.y--;
0265:                                        StringBuilder lineBuffer = commandLines
0266:                                                .getEditableLines().get(
0267:                                                        cursorPosition.y);
0268:                                        cursorPosition.x = lineBuffer.length();
0269:                                        lineBuffer.append(line);
0270:                                    }
0271:                                } else {
0272:                                    StringBuilder tmp = getEditableCommand()
0273:                                            .getEditableLines().get(
0274:                                                    cursorPosition.y);
0275:                                    if (cursorPosition.x > 0) {
0276:                                        tmp.deleteCharAt(cursorPosition.x - 1);
0277:                                        cursorPosition.x--;
0278:                                    }
0279:                                }
0280:                            }
0281:
0282:                            public CharSequence getHelp() {
0283:                                return "Backspace:\tRemove the character before the cursor position";
0284:                            }
0285:                        });
0286:                actionKeys.put(Integer.toString(InputChar.KEY_DC),
0287:                        new KeyAction() {
0288:                            public void execute() {
0289:                                StringBuilder lineBuffer = commandLines
0290:                                        .getEditableLines().get(
0291:                                                cursorPosition.y);
0292:                                if (cursorPosition.x < lineBuffer.length()) {
0293:                                    StringBuilder tmp = getEditableCommand()
0294:                                            .getEditableLines().get(
0295:                                                    cursorPosition.y);
0296:                                    tmp.deleteCharAt(cursorPosition.x);
0297:                                }
0298:                            }
0299:
0300:                            public CharSequence getHelp() {
0301:                                return "Del:\tDelete the charactor at the current cursor position";
0302:                            }
0303:                        });
0304:                actionKeys.put("", new KeyAction() {
0305:                    public void execute() {
0306:                        StringBuilder lineBuffer = commandLines
0307:                                .getEditableLines().get(cursorPosition.y);
0308:                        int previousBreak = SQLUtil
0309:                                .getLastBreakIndex(lineBuffer.substring(0,
0310:                                        cursorPosition.x));
0311:                        lineBuffer.delete(previousBreak, cursorPosition.x);
0312:                        cursorPosition.x = previousBreak;
0313:                    }
0314:
0315:                    public CharSequence getHelp() {
0316:                        return "Control-W:\tRemove word before cursor position";
0317:                    }
0318:                });
0319:                actionKeys.put("", new KeyAction() { // ctrl+u
0320:                            public void execute() {
0321:                                if (cursorPosition.x > 0) {
0322:                                    StringBuilder lineBuffer = commandLines
0323:                                            .getEditableLines().get(
0324:                                                    cursorPosition.y);
0325:                                    lineBuffer.delete(0, cursorPosition.x);
0326:                                    cursorPosition.x = 0;
0327:                                } else if (cursorPosition.y > 0) {
0328:                                    StringBuilder lineBuffer = commandLines
0329:                                            .getEditableLines().get(
0330:                                                    cursorPosition.y);
0331:                                    if (lineBuffer.length() == 0) {
0332:                                        commandLines.getEditableLines().remove(
0333:                                                cursorPosition.y);
0334:                                    }
0335:                                    cursorPosition.y--;
0336:                                    lineBuffer = commandLines
0337:                                            .getEditableLines().get(
0338:                                                    cursorPosition.y);
0339:                                    lineBuffer.delete(0, lineBuffer.length());
0340:                                }
0341:                            }
0342:
0343:                            public CharSequence getHelp() {
0344:                                return "Control-U:\tRemove all characters before the cursor position";
0345:                            }
0346:                        });
0347:                actionKeys.put(Integer.toString(InputChar.KEY_PPAGE),
0348:                        new KeyAction() {
0349:                            public void execute() {
0350:                                if ((screenBuffer.size()
0351:                                        + commandLines.getLines().size() - (Toolkit
0352:                                        .getScreenHeight() / 2)
0353:                                        * pageUpCount) > 0) {
0354:                                    pageUpCount++;
0355:
0356:                                }
0357:                            }
0358:
0359:                            public CharSequence getHelp() {
0360:                                return "PageUp:\tMove back in screen history";
0361:                            }
0362:                        });
0363:                actionKeys.put(Integer.toString(InputChar.KEY_NPAGE),
0364:                        new KeyAction() {
0365:                            public void execute() {
0366:                                if (pageUpCount > 0) {
0367:                                    pageUpCount--;
0368:                                }
0369:                            }
0370:
0371:                            public CharSequence getHelp() {
0372:                                return "PageDown:\tMove forward in screen history";
0373:                            }
0374:                        });
0375:                actionKeys.put("", new KeyAction() { // ctrl+a
0376:                            public void execute() {
0377:                                output("Abort requested");
0378:                                if (commandThread.isAlive()
0379:                                        && commandThread.getCommand().abort()) {
0380:                                    output("Abort done..");
0381:                                }
0382:                            }
0383:
0384:                            public CharSequence getHelp() {
0385:                                return "Control-A:\tAbort current command (if it is supported by that command)";
0386:                            }
0387:                        });
0388:                actionKeys.put("", new KeyAction() { //Ctrl+D
0389:                            public void execute() {
0390:                                if (commandLines.getCommandString().length() == 0) { //Quit on empty commandline, ignore otherwise
0391:                                    executeCommand(new InputCommand("quit"));
0392:                                }
0393:                            }
0394:
0395:                            public CharSequence getHelp() {
0396:                                return "Control-D:\tExit sqlshell";
0397:                            }
0398:                        });
0399:
0400:                MAX_LINE_LENGTH = Toolkit.getScreenWidth()
0401:                        - (PROMPT.length() + 2 + 1); // prompt + "> "
0402:
0403:                output("Welcome to the SQLShell client.");
0404:                output("Type 'help' to get a list of available commands other then the default sql input.");
0405:            }
0406:
0407:            /**
0408:             * Returns the connection to the database
0409:             * @return the connection to the database
0410:             */
0411:            public Connection getConnection() {
0412:                return DBConnector.getInstance().getConnection();
0413:            }
0414:
0415:            /**
0416:             * Shows this window.
0417:             * Override to make sure paint content is called.
0418:             */
0419:            @Override
0420:            public void show() {
0421:                super .show();
0422:                paint();
0423:            }
0424:
0425:            /**
0426:             * Hides this window.
0427:             * Override to make sure the spool writer is closed when it was open
0428:             */
0429:            @Override
0430:            public void hide() {
0431:                try {
0432:                    if (spoolWriter != null) {
0433:                        try {
0434:                            spoolWriter.close();
0435:                            spoolWriter = null;
0436:                        } catch (Exception e) {/*ignore*/
0437:                        }
0438:                    }
0439:                } finally {
0440:                    super .hide();
0441:                }
0442:            }
0443:
0444:            /**
0445:             * Returns a string representation of the current command.
0446:             * @return a string representation of the current command.
0447:             */
0448:            private SQLCommand getCommand() {
0449:                return commandLines;
0450:            }
0451:
0452:            /**
0453:             * Add a new line to the command lines buffer.
0454:             */
0455:            private StringBuilder newLine() {
0456:                cursorPosition.x = 0;
0457:                StringBuilder newLine = new StringBuilder();
0458:                getEditableCommand().getEditableLines().add(newLine);
0459:                cursorPosition.y = commandLines.getLines().size() - 1;
0460:                return newLine;
0461:            }
0462:
0463:            /**
0464:             * Handle key input.
0465:             * @param inp the character that is being pressed by the user.
0466:             */
0467:            protected void handleInput(InputChar inp) {
0468:                //debug("Input: " + inp.getCode());
0469:                try {
0470:                    if (inp.getCode() != InputChar.KEY_PPAGE
0471:                            && inp.getCode() != InputChar.KEY_NPAGE) {
0472:                        pageUpCount = 0; // some character entered, so reset pageup count
0473:                    }
0474:                    if (inp.isSpecialCode()) {
0475:                        KeyAction ke = actionKeys.get(Integer.toString(inp
0476:                                .getCode()));// || inp.toString().equals("") || inp.toString().equals("")) {
0477:                        if (ke != null) {
0478:                            ke.execute();
0479:                        } else {
0480:                            debug("Unknown character: " + inp.getCode());
0481:                        }
0482:                    } else {
0483:                        KeyAction ke = actionKeys.get(inp.toString());
0484:                        if (ke != null) {
0485:                            ke.execute();
0486:                        } else {
0487:                            if (inp.getCharacter() == '\n') { // newline... see if the command can be executed
0488:                                // execute the command
0489:                                SQLCommand sqlCommand = getCommand();
0490:                                String command = sqlCommand.getCommandString();
0491:                                // search command...
0492:                                if (command.length() > 0
0493:                                        && command.charAt(0) == '/') { // search in history
0494:                                    String matchPattern = ".*"
0495:                                            + command.substring(1, command
0496:                                                    .length()) + ".*";
0497:                                    for (int cIndex = commandHistory.size() - 1; cIndex >= 0; cIndex--) {
0498:                                        if (cIndex == commandIndex) {
0499:                                            continue; // skip current command
0500:                                        }
0501:                                        SQLCommand newSqlCommand = commandHistory
0502:                                                .get(cIndex);
0503:                                        String commandString = newSqlCommand
0504:                                                .getCommandString();
0505:                                        if (commandString.matches(matchPattern)) {
0506:                                            commandHistory.remove(commandIndex);
0507:                                            commandIndex = commandHistory
0508:                                                    .indexOf(newSqlCommand);
0509:                                            commandLines = newSqlCommand;
0510:                                            cursorPosition.y = 0;
0511:                                            cursorPosition.x = 0;
0512:                                            paint(); // force repaint
0513:                                            return;
0514:                                        }
0515:                                    }
0516:                                    Toolkit.beep(); // TODO clear search??
0517:                                    return;
0518:                                } else if (executeCommand(sqlCommand)) {
0519:                                    // clear command history
0520:                                    if (commandIndex != commandHistory.size() - 1) {
0521:                                        SQLCommand tmpLines = commandLines;
0522:                                        commandLines = commandHistory
0523:                                                .get(commandHistory.size() - 1);
0524:                                        if (commandLines.getCommandString()
0525:                                                .equals("")) {
0526:                                            commandHistory.add(commandHistory
0527:                                                    .size() - 1, tmpLines);
0528:                                        } else {
0529:                                            commandHistory.add(tmpLines);
0530:                                            commandLines = tmpLines;
0531:                                        }
0532:                                    }
0533:                                    if (!commandLines.getCommandString()
0534:                                            .equals("")) {
0535:                                        commandLines = new SQLCommand();
0536:                                        commandHistory.add(commandLines);
0537:                                        newLine();
0538:                                    }
0539:                                    commandIndex = commandHistory.size() - 1;
0540:                                    cursorPosition.y = commandLines.getLines()
0541:                                            .size() - 1;
0542:                                    cursorPosition.x = commandLines.getLines()
0543:                                            .get(cursorPosition.y).length();
0544:                                    paint(); // force repaint
0545:                                    return;
0546:                                }
0547:                            }
0548:                            CharSequence newText;
0549:                            if (inp.getCharacter() == '\t') {
0550:                                try {
0551:                                    newText = getTabCompletion(commandLines,
0552:                                            cursorPosition);
0553:                                } catch (IllegalStateException e) {
0554:                                    output(getCommand().getCommandString()); // add command as well...
0555:                                    error(e);
0556:                                    return;
0557:                                }
0558:                            } else {
0559:                                newText = Character
0560:                                        .toString(inp.getCharacter());
0561:                            }
0562:                            if (newText.equals("\n")) {
0563:                                newLine(); // TODO Fix return in middle of an other line
0564:                            } else {
0565:                                List<StringBuilder> editableLines = getEditableCommand()
0566:                                        .getEditableLines();
0567:                                StringBuilder currentLine = editableLines
0568:                                        .get(cursorPosition.y);
0569:                                currentLine.insert(cursorPosition.x, newText);
0570:                                cursorPosition.x += newText.length();
0571:                                // check if the new line is becoming too long
0572:                                if (currentLine.length() > MAX_LINE_LENGTH) {
0573:                                    // TODO search for lastspace that is not between '' ??
0574:                                    int lastSpace = currentLine
0575:                                            .lastIndexOf(" ");
0576:                                    // check if there are enough 'next' lines
0577:                                    // if not.. add one
0578:                                    if (editableLines.size() - 1 == cursorPosition.y) {
0579:                                        StringBuilder newLine = new StringBuilder();
0580:                                        editableLines.add(newLine);
0581:                                    }
0582:                                    // check if the nextline has enough room for the new word
0583:                                    // if not.. add a new line
0584:                                    if (editableLines.get(cursorPosition.y + 1)
0585:                                            .length()
0586:                                            + (currentLine.length() - lastSpace + 1) > MAX_LINE_LENGTH) {
0587:                                        StringBuilder newLine = new StringBuilder();
0588:                                        editableLines.add(cursorPosition.y + 1,
0589:                                                newLine);
0590:                                    }
0591:                                    // fetch the next line
0592:                                    StringBuilder nextLine = editableLines
0593:                                            .get(cursorPosition.y + 1);
0594:                                    // if the nextline already has some text.. add a space in front of it
0595:                                    if (nextLine.length() > 0) {
0596:                                        nextLine.insert(0, ' ');
0597:                                    }
0598:                                    // insert the new text at the beginning
0599:                                    nextLine.insert(0, currentLine
0600:                                            .subSequence(lastSpace + 1,
0601:                                                    currentLine.length()));
0602:                                    currentLine.delete(lastSpace, currentLine
0603:                                            .length());
0604:                                    // check if the cursor postition > the new line length
0605:                                    // calculate new x and go to nextline
0606:                                    if (cursorPosition.x >= lastSpace) {
0607:                                        cursorPosition.x = cursorPosition.x
0608:                                                - (lastSpace + 1);
0609:                                        cursorPosition.y++;
0610:                                    }
0611:                                }
0612:                            }
0613:                        }
0614:                    }
0615:                } catch (Throwable t) {
0616:                    error(t);
0617:                }
0618:                paint();
0619:            }
0620:
0621:            /**
0622:             * Return the editable version of the commandlines.
0623:             * If editing a previous command clone it and return the clone
0624:             * @return the editable version of the commandlines.
0625:             */
0626:            protected SQLCommand getEditableCommand() {
0627:                if (commandHistory.indexOf(commandLines) != commandHistory
0628:                        .size() - 1) {
0629:                    List<? extends CharSequence> tmp = commandLines.getLines();
0630:                    if (commandHistory.get(commandHistory.size() - 1)
0631:                            .getLines().size() == 1
0632:                            && commandHistory.get(commandHistory.size() - 1)
0633:                                    .getLines().get(0).length() == 0) {
0634:                        commandLines = commandHistory
0635:                                .get(commandHistory.size() - 1);
0636:                        commandLines.getEditableLines().remove(0);
0637:                    } else {
0638:                        commandLines = new SQLCommand();
0639:                        commandHistory.add(commandLines);
0640:                    }
0641:                    for (int i = 0; i < tmp.size(); i++) {
0642:                        commandLines.getEditableLines().add(
0643:                                new StringBuilder(tmp.get(i)));
0644:                    }
0645:                    commandIndex = commandHistory.size() - 1;
0646:                }
0647:                return commandLines;
0648:            }
0649:
0650:            /**
0651:             * Output data to the screen.
0652:             * @param data the data to print to the screen.
0653:             */
0654:            protected synchronized void output(CharSequence data) {
0655:                screenBuffer.addAll(getLines(data));
0656:                if (spoolWriter != null) {
0657:                    try {
0658:                        spoolWriter.write(data.toString());
0659:                        spoolWriter.write("\n");
0660:                    } catch (IOException e) {
0661:                        screenBuffer
0662:                                .add("WARNING: Could not write to spool file");
0663:                        error(e);
0664:                    }
0665:                }
0666:            }
0667:
0668:            /**
0669:             * Output error exception to the screen.
0670:             * @param e the error to print to the screen
0671:             */
0672:            protected synchronized void error(Throwable e) {
0673:                output(e.getMessage() == null ? e.toString() : e.getMessage());
0674:                StringWriter sw = new StringWriter();
0675:                e.printStackTrace(new PrintWriter(sw));
0676:                sw.flush();
0677:                lastExceptionDetails = sw.toString();
0678:            }
0679:
0680:            /**
0681:             * Return a list of table names available for the current connection.
0682:             * @return a list of table names available for the current connection.
0683:             */
0684:            protected List<String> getTableNames() {
0685:                List<String> returnValue = new ArrayList<String>();
0686:                try {
0687:                    ResultSet rs = getConnection().getMetaData().getTables(
0688:                            getConnection().getCatalog(),
0689:                            DBConnector.getInstance().getSchema(), null,
0690:                            new String[] { "TABLE" });
0691:                    while (rs.next()) {
0692:                        if (!returnValue.contains(rs.getString("TABLE_NAME"))) {
0693:                            returnValue.add(rs.getString("TABLE_NAME"));
0694:                        }
0695:                    }
0696:                    return returnValue;
0697:                } catch (SQLException ex) {
0698:                    ex.printStackTrace();
0699:                    Logger.getLogger(SQLShell.class.getName()).log(
0700:                            Level.SEVERE, null, ex);
0701:                    return null;
0702:                }
0703:            }
0704:
0705:            /**
0706:             * Return a list of column names for the specified list of table names.
0707:             * @param tableNames a list of tableNames
0708:             * @return a list of column names for the specified list of table names.
0709:             */
0710:            protected List<String> getColumnNames(List<String> tableNames) {
0711:                List<String> returnValues = new ArrayList<String>();
0712:                Iterator<String> iTableNames = tableNames.iterator();
0713:                while (iTableNames.hasNext()) {
0714:                    String tableName = DBConnector.getInstance()
0715:                            .translateDbVar(iTableNames.next().trim());
0716:                    try {
0717:                        ResultSet rs = getConnection().getMetaData()
0718:                                .getColumns(getConnection().getCatalog(),
0719:                                        DBConnector.getInstance().getSchema(),
0720:                                        tableName, "%");
0721:                        while (rs.next()) {
0722:                            if (!returnValues.contains(rs
0723:                                    .getString("COLUMN_NAME"))) {
0724:                                returnValues.add(rs.getString("COLUMN_NAME"));
0725:                            }
0726:                        }
0727:                    } catch (SQLException ex) {
0728:                        throw new IllegalStateException(
0729:                                "Failed to find columnnames for table: "
0730:                                        + tableName, ex);
0731:                    }
0732:                }
0733:                return returnValues;
0734:            }
0735:
0736:            /**
0737:             * Try to find a match in the provided list starging with sub.
0738:             * If more matches apply show the user a dialog to choose a match or simply display all matches in the window
0739:             * @param values all possible values to choose from (not limited with the sub parameter)
0740:             * @param sub the start of the match
0741:             * @return the match starting with sub minus the sub itself in the correct casing
0742:             */
0743:            protected CharSequence findMatch(List<String> values, String sub) {
0744:                List<String> matches = new ArrayList<String>();
0745:                Iterator<String> iValues = values.iterator();
0746:                while (iValues.hasNext()) {
0747:                    String value = iValues.next();
0748:                    if (value.toUpperCase().startsWith(sub.toUpperCase())) {
0749:                        matches.add(value);
0750:                    }
0751:                }
0752:                //debug("Matches found: "+ matches.size() +" --> "+ sub +" / "+ values);
0753:                String match = null;
0754:                if (matches.size() == 1) {
0755:                    match = matches.get(0);
0756:                } else if (matches.size() > 1
0757:                        && matches.size() < MAX_MATCH_SIZE) {
0758:                    int y;
0759:                    if (screenBuffer.size() + cursorPosition.y > Toolkit
0760:                            .getScreenHeight() - 3) {
0761:                        y = Toolkit.getScreenHeight() - 4;
0762:                    } else {
0763:                        y = screenBuffer.size() + cursorPosition.y;
0764:                    }
0765:                    PopUpMenu menu = new PopUpMenu(cursorPosition.x, Math.max(
0766:                            2, y - matches.size()), "Find match");
0767:                    Iterator<String> iMatches = matches.iterator();
0768:                    while (iMatches.hasNext()) {
0769:                        menu.add(iMatches.next());
0770:                    }
0771:                    menu.show();
0772:                    match = menu.getSelectedItem();
0773:                } else if (matches.size() > 1) {
0774:                    output("\n" + toColumns(matches));
0775:                }
0776:                if (match != null) {
0777:                    if (sub.length() > 0) {
0778:                        if (Character.isUpperCase(sub.charAt(0))) {
0779:                            match = match.toUpperCase();
0780:                        } else {
0781:                            match = match.toLowerCase();
0782:                        }
0783:                    }
0784:                    return match.substring(sub.length());
0785:                }
0786:                return null;
0787:            }
0788:
0789:            /**
0790:             * Simple method to change a null value to an empty charsequence.
0791:             * @param s the charsequence to convert to empty if it is null
0792:             * @return empty when s was null or return s when s is not null
0793:             */
0794:            protected CharSequence nullToEmpty(CharSequence s) {
0795:                if (s == null) {
0796:                    return "";
0797:                }
0798:                return s;
0799:            }
0800:
0801:            /**
0802:             * return the tab completion value.
0803:             * @param commandLines the current command
0804:             * @param cursorPosition the position where the tab completion was invocated
0805:             * @return the tab completion value.
0806:             */
0807:            protected CharSequence getTabCompletion(SQLCommand commandLines,
0808:                    Point cursorPosition) {
0809:                TabCompletionInfo info = null;
0810:                String cmd = commandLines.getCommandString();
0811:                if (cmd.length() > 0) {
0812:                    if (cmd.indexOf(' ') > 0) {
0813:                        cmd = cmd.substring(0, cmd.indexOf(' ')).trim();
0814:                    }
0815:                    Command tmpCommand = commands.findCommand(cmd);
0816:                    if (tmpCommand == null) {
0817:                        for (Command c : commands.getCommands()) {
0818:                            if (cmd.equalsIgnoreCase(c.getCommandString()
0819:                                    .toString())) {
0820:                                tmpCommand = c;
0821:                                break;
0822:                            }
0823:                        }
0824:                    }
0825:                    if (tmpCommand != null) {
0826:                        info = tmpCommand.getTabCompletionInfo(commandLines,
0827:                                cursorPosition);
0828:                    }
0829:                }
0830:                if (info == null) {
0831:                    info = SQLUtil.getTabCompletionInfo(commandLines,
0832:                            cursorPosition);
0833:                }
0834:                if (info.getMatchType() == TabCompletionInfo.MatchType.SQL_KEYWORD) {
0835:                    return nullToEmpty(findMatch(info.getPossibleMatches(),
0836:                            info.getStart()));
0837:                }
0838:                if (info.getMatchType() == TabCompletionInfo.MatchType.TABLE_NAMES) {
0839:                    //debug("table completion for \""+info.getStart()+"\"");
0840:                    return nullToEmpty(findMatch(getTableNames(), info
0841:                            .getStart()));
0842:                }
0843:                if (info.getMatchType() == TabCompletionInfo.MatchType.COLUMN_NAMES) {
0844:                    return nullToEmpty(findMatch(getColumnNames(info
0845:                            .getPossibleMatches()), info.getStart()));
0846:                }
0847:                if (info.getMatchType() == TabCompletionInfo.MatchType.UNKNOWN) {
0848:                    return nullToEmpty(findMatch(info.getPossibleMatches(),
0849:                            info.getStart()));
0850:                }
0851:                Toolkit.beep();
0852:                return "";
0853:            }
0854:
0855:            /**
0856:             * (Try) to execute a command) and return true if it succeeded.
0857:             * @param command the command to try and execute
0858:             * @return true if it succeeded.
0859:             */
0860:            protected boolean executeCommand(SQLCommand sqlCommand) {
0861:                return executeCommand(sqlCommand, false);
0862:            }
0863:
0864:            private boolean executeCommand(final SQLCommand sqlCommand,
0865:                    boolean direct) {
0866:                final String commandString = sqlCommand.getCommandString();
0867:                if (commandString.equalsIgnoreCase("printStackTrace")) {
0868:                    if (lastExceptionDetails == null) {
0869:                        output("No known last exception to print");
0870:                    } else {
0871:                        output(lastExceptionDetails);
0872:                    }
0873:                    return true;
0874:                }
0875:                Command command = createCommand(commandString); // first try to find a match without ;
0876:                if (command == null) {
0877:                    command = createCommand(sqlCommand
0878:                            .getUntrimmedCommandString()); // then with ; for sql statements...
0879:                }
0880:                if (command == null) {
0881:                    return false;
0882:                }
0883:                // make sure only one command is run at once
0884:                if (commandThread != null && commandThread.isAlive()) {
0885:                    try {
0886:                        commandThread.join();
0887:                    } catch (InterruptedException ex) {
0888:                        Logger.getLogger(SQLShell.class.getName()).log(
0889:                                Level.SEVERE, null, ex);
0890:                    }
0891:                }
0892:                output(commandString);
0893:                if (direct || !command.backgroundProcessSupported()) {
0894:                    output(command.execute(sqlCommand));
0895:                } else {
0896:                    commandThread = new CommandThread(command) {
0897:                        @Override
0898:                        void execute() {
0899:                            output(getCommand().execute(sqlCommand));
0900:                        }
0901:                    };
0902:                    commandThread.start();
0903:                }
0904:                return true;
0905:            }
0906:
0907:            private Command createCommand(String commandString) {
0908:                Command command = commands.findCommand(commandString);
0909:                if (command != null) {
0910:                    return command;
0911:                }
0912:                if (commandString.matches(".*;[\\s]*")) {
0913:                    return new QueryCommand(); // TODO is this ever reached???
0914:                }
0915:                return null;
0916:            }
0917:
0918:            /**
0919:             * Paint the screen.
0920:             */
0921:            @Override
0922:            protected synchronized void paint() {
0923:                CharColor color = new CharColor(CharColor.BLACK,
0924:                        CharColor.WHITE, CharColor.BOLD, CharColor.BOLD);
0925:
0926:                List<CharSequence> tmpList = new ArrayList<CharSequence>();
0927:                tmpList.addAll(screenBuffer);
0928:
0929:                //add prompt
0930:                List<? extends CharSequence> currentLines = commandLines
0931:                        .getLines();
0932:                for (int i = 0; i < currentLines.size(); i++) {
0933:                    if (i == 0 && showPrompt) {
0934:                        tmpList.add(PROMPT + "> " + currentLines.get(i));
0935:                    } else {
0936:                        String nrI = Integer.toString(i + 1);
0937:                        tmpList.add(emptyLine.substring(0, PROMPT.length()
0938:                                - nrI.length())
0939:                                + nrI + "> " + currentLines.get(i));
0940:                    }
0941:                }
0942:                int startLine;
0943:                if (tmpList.size() > Toolkit.getScreenHeight() - 1) {
0944:                    startLine = tmpList.size()
0945:                            - (Toolkit.getScreenHeight() - 1);
0946:                    if (pageUpCount > 0) {
0947:                        startLine -= (pageUpCount * Toolkit.getScreenHeight() / 2);
0948:                        if (startLine < 0) {
0949:                            startLine = 0;
0950:                        }
0951:                    }
0952:                } else {
0953:                    startLine = 0;
0954:                }
0955:                int lineNr;
0956:                for (lineNr = startLine; lineNr < tmpList.size()
0957:                        && lineNr - startLine < Toolkit.getScreenHeight() - 1; lineNr++) {
0958:                    CharSequence linePart = tmpList.get(lineNr);
0959:                    String line = linePart
0960:                            + emptyLine.substring(linePart.length());
0961:                    Toolkit.printString(line, 0, lineNr - startLine, color);
0962:                }
0963:                for (int lNr = lineNr; lNr < Toolkit.getScreenHeight(); lNr++) {
0964:                    Toolkit.printString(emptyLine, 0, lNr, color);
0965:                }
0966:
0967:                // paint cursor
0968:                color = new CharColor(CharColor.BLACK, CharColor.WHITE,
0969:                        CharColor.REVERSE, CharColor.REVERSE);
0970:                String cursorChar = " ";
0971:                if (commandLines.getLines().size() > 0) {
0972:                    String tmp = commandLines.getLines().get(cursorPosition.y)
0973:                            .toString();
0974:                    if (cursorPosition.x < tmp.length()) {
0975:                        cursorChar = tmp.substring(cursorPosition.x,
0976:                                cursorPosition.x + 1);
0977:                    }
0978:                }
0979:                Toolkit.printString(cursorChar, PROMPT.length() + "> ".length()
0980:                        + cursorPosition.x, lineNr
0981:                        - (commandLines.getLines().size() - cursorPosition.y)
0982:                        - startLine, color);
0983:            }
0984:
0985:            private void debug(String debug) {
0986:                CharColor color = new CharColor(CharColor.BLUE,
0987:                        CharColor.YELLOW);
0988:                Toolkit.printString(debug, 1, Toolkit.getScreenHeight() - 1,
0989:                        color);
0990:            }
0991:
0992:            /**
0993:             * Method to convert a long string to a displayable list of strings with a max with of the screen width.
0994:             * @param text a (long) string
0995:             * @return the text devided into multiple lines to match the screen width
0996:             */
0997:            private static List<CharSequence> getLines(CharSequence text) {
0998:                int maxWidth = Toolkit.getScreenWidth();
0999:                List<CharSequence> list = new ArrayList<CharSequence>();
1000:                StringBuilder buffer = new StringBuilder();
1001:                for (int i = 0; i < text.length(); i++) {
1002:                    char c = text.charAt(i);
1003:                    if (c == '\n' || buffer.length() == maxWidth) {
1004:                        String line = buffer.toString();
1005:                        list.add(line);
1006:                        buffer = new StringBuilder();
1007:                        if (c != '\n') {
1008:                            buffer.append(c);
1009:                        }
1010:                    } else if (c == '\r') {
1011:                        //ignore
1012:                    } else {
1013:                        buffer.append(c);
1014:                    }
1015:                }
1016:                if (buffer.length() > 0) {
1017:                    list.add(buffer.toString());
1018:                }
1019:                return list;
1020:            }
1021:
1022:            /**
1023:             * Convert a list to a presentable text devided into multiple columns.
1024:             */
1025:            private StringBuilder toColumns(List<? extends CharSequence> values) {
1026:                int maxWidth = 0;
1027:                Iterator<? extends CharSequence> iValues = values.iterator();
1028:                while (iValues.hasNext()) {
1029:                    maxWidth = Math.max(maxWidth, iValues.next().length());
1030:                }
1031:                maxWidth += 2;// add extra space
1032:                int nrOfColumns = (Toolkit.getScreenWidth()) / maxWidth;
1033:                StringBuilder returnValue = new StringBuilder();
1034:                for (int row = 0; row < values.size(); row += nrOfColumns) {
1035:                    for (int col = 0; col < nrOfColumns
1036:                            && row + col < values.size(); col++) {
1037:                        returnValue.append(values.get(row + col)
1038:                                + emptyLine.substring(0, maxWidth
1039:                                        - values.get(row + col).length()));
1040:                    }
1041:                    returnValue.append('\n');
1042:                }
1043:                return returnValue;
1044:            }
1045:
1046:            /**
1047:             * A list which contains a limited number of lines.
1048:             */
1049:            private class LimitedArrayList<E> extends ArrayList<E> {
1050:                private int maxSize;
1051:
1052:                /**
1053:                 * Constructor.
1054:                 * @param maxSize the maximum number of lines the list may contain
1055:                 */
1056:                public LimitedArrayList(int maxSize) {
1057:                    super (maxSize); // some sane default
1058:                    this .maxSize = maxSize;
1059:                }
1060:
1061:                @Override
1062:                public boolean add(E object) {
1063:                    if (size() == maxSize) {
1064:                        remove(0);
1065:                    }
1066:                    return super .add(object);
1067:                }
1068:
1069:                @Override
1070:                public void add(int index, E object) {
1071:                    if (size() == maxSize) {
1072:                        remove(0);
1073:                    }
1074:                    super .add(index, object);
1075:                }
1076:            }
1077:
1078:            /**
1079:             * Connect command for setting up a connection to a database.
1080:             */
1081:            private static class ConnectCommand implements  Command {
1082:                /**
1083:                 * Execute the connection command and return a readable result.
1084:                 * @param command the command string for setting up a connection
1085:                 * @return a readable result of the execution of this command.
1086:                 */
1087:                @Override
1088:                public CharSequence execute(SQLCommand cmd) {
1089:                    String command = cmd.getCommandString();
1090:                    try {
1091:                        String cmdString = command
1092:                                .substring("connect".length()).trim();
1093:                        if (cmdString.length() > 0
1094:                                && cmdString.charAt(cmdString.length() - 1) == ';') {
1095:                            cmdString = cmdString.substring(0, cmdString
1096:                                    .length() - 1);
1097:                        }
1098:                        DBConnector.getInstance().connect(cmdString);
1099:                        return "Connected.\n\n";
1100:                    } catch (SQLException e) {
1101:                        throw new IllegalStateException("Failed to connect: "
1102:                                + e.getMessage(), e);
1103:                    }
1104:                }
1105:
1106:                @Override
1107:                public CharSequence getCommandString() {
1108:                    return "connect";
1109:                }
1110:
1111:                /**
1112:                 * Returns some tab completion info for the specified command.
1113:                 * @param commandInfo the command lines
1114:                 * @param commandPoint the cursor position
1115:                 * @return some tab completion info for the specified command.
1116:                 */
1117:                @Override
1118:                public TabCompletionInfo getTabCompletionInfo(
1119:                        SQLCommand command, Point commandPoint) {
1120:                    return null;
1121:                }
1122:
1123:                @Override
1124:                public CharSequence getHelp() {
1125:                    StringBuffer buf = new StringBuffer();
1126:                    Iterator<String> idents = DBConnector.getInstance()
1127:                            .getPredefinedConnectionIdentifiers().iterator();
1128:                    while (idents.hasNext()) {
1129:                        buf.append(' ');
1130:                        String ident = idents.next();
1131:                        buf.append(ident);
1132:                        if (ident.equals(DBConnector.getInstance()
1133:                                .getDefaultIdentifier())) {
1134:                            buf.append(" *");
1135:                        }
1136:                        if (idents.hasNext()) {
1137:                            buf.append('\n');
1138:                        }
1139:                    }
1140:                    return "Create a conection to the database\n"
1141:                            + " user/pass@ident -> connect the user with password pass to the ident\n"
1142:                            + " user/@ident     -> connect the user with an empty password pass to the ident\n"
1143:                            + " user@ident      -> connect the user to the ident and prompt for password\n"
1144:                            + " @ident          -> connect to the ident connection.\n"
1145:                            + "                    If default user and/or password are specified these will be used, \n"
1146:                            + "                    otherwise you will be prompted for a username and/or password.\n"
1147:                            + "Currently configured connection identifiers:\n"
1148:                            + buf.toString();
1149:                }
1150:
1151:                @Override
1152:                public boolean abort() {
1153:                    return false;// not implemented
1154:                }
1155:
1156:                @Override
1157:                public boolean backgroundProcessSupported() {
1158:                    return false;
1159:                }
1160:            }
1161:
1162:            /**
1163:             * Command that enables the user to close a connection.
1164:             */
1165:            private static class DisConnectCommand implements  Command {
1166:                @Override
1167:                public CharSequence execute(SQLCommand cmd) {
1168:                    try {
1169:                        DBConnector.getInstance().disconnect();
1170:                        return "Disconnected.\n\n";
1171:                    } catch (SQLException e) {
1172:                        throw new IllegalStateException(
1173:                                "Failed to disconnect: " + e.getMessage(), e);
1174:                    }
1175:                }
1176:
1177:                @Override
1178:                public CharSequence getCommandString() {
1179:                    return "disconnect";
1180:                }
1181:
1182:                /**
1183:                 * Returns some tab completion info for the specified command.
1184:                 * @param commandInfo the command lines
1185:                 * @param commandPoint the cursor position
1186:                 * @return some tab completion info for the specified command.
1187:                 */
1188:                @Override
1189:                public TabCompletionInfo getTabCompletionInfo(
1190:                        SQLCommand command, Point commandPoint) {
1191:                    return null;
1192:                }
1193:
1194:                @Override
1195:                public CharSequence getHelp() {
1196:                    return "Close the current conection to the database";
1197:                }
1198:
1199:                @Override
1200:                public boolean abort() {
1201:                    return false;// not implemented
1202:                }
1203:
1204:                @Override
1205:                public boolean backgroundProcessSupported() {
1206:                    return false;
1207:                }
1208:            }
1209:
1210:            /**
1211:             * Some basic window settings like resize.
1212:             */
1213:            private class WindowCommand implements  Command {
1214:                @Override
1215:                public CharSequence execute(SQLCommand cmd) {
1216:                    String command = cmd.getCommandString();
1217:                    String argument = command.trim().substring(
1218:                            "window".length()).trim();
1219:                    if (argument.equalsIgnoreCase("resize")) {
1220:                        resize(Toolkit.getScreenWidth(), Toolkit
1221:                                .getScreenHeight());
1222:                        return "Window resized to " + Toolkit.getScreenWidth()
1223:                                + "x" + Toolkit.getScreenHeight();
1224:                    }
1225:                    return "Uknown command '" + argument + "'";
1226:                }
1227:
1228:                @Override
1229:                public CharSequence getCommandString() {
1230:                    return "window";
1231:                }
1232:
1233:                /**
1234:                 * Returns some tab completion info for the specified command.
1235:                 * @param commandInfo the command lines
1236:                 * @param commandPoint the cursor position
1237:                 * @return some tab completion info for the specified command.
1238:                 */
1239:                @Override
1240:                public TabCompletionInfo getTabCompletionInfo(
1241:                        SQLCommand command, Point commandPoint) {
1242:                    return null;
1243:                }
1244:
1245:                @Override
1246:                public CharSequence getHelp() {
1247:                    return "window resize: notify the sql client of a screen resize";
1248:                }
1249:
1250:                @Override
1251:                public boolean abort() {
1252:                    return false;// not implemented
1253:                }
1254:
1255:                @Override
1256:                public boolean backgroundProcessSupported() {
1257:                    return false;
1258:                }
1259:            }
1260:
1261:            /**
1262:             * Provide a list of commands executed.
1263:             */
1264:            private class HistoryCommand implements  Command {
1265:                @Override
1266:                public CharSequence execute(SQLCommand command) {
1267:                    StringBuilder returnValue = new StringBuilder();
1268:                    Iterator<SQLCommand> iCommands = commandHistory.iterator();
1269:                    while (iCommands.hasNext()) {
1270:                        SQLCommand cmd = iCommands.next();
1271:                        returnValue.append(cmd.getCommandString());
1272:                        returnValue.append('\n');
1273:                    }
1274:                    return returnValue;
1275:                }
1276:
1277:                @Override
1278:                public CharSequence getCommandString() {
1279:                    return "history";
1280:                }
1281:
1282:                /**
1283:                 * Returns some tab completion info for the specified command.
1284:                 * @param commandInfo the command lines
1285:                 * @param commandPoint the cursor position
1286:                 * @return some tab completion info for the specified command.
1287:                 */
1288:                @Override
1289:                public TabCompletionInfo getTabCompletionInfo(
1290:                        SQLCommand command, Point commandPoint) {
1291:                    return null;
1292:                }
1293:
1294:                @Override
1295:                public CharSequence getHelp() {
1296:                    return "Show history of executed statements\n"
1297:                            + "By using '/<search>' you can search the command history";
1298:                }
1299:
1300:                @Override
1301:                public boolean abort() {
1302:                    return false;// not implemented
1303:                }
1304:
1305:                @Override
1306:                public boolean backgroundProcessSupported() {
1307:                    return false;
1308:                }
1309:            }
1310:
1311:            /**
1312:             * Exit the client.
1313:             */
1314:            private class QuitCommand implements  Command {
1315:                private String cmd;
1316:
1317:                public QuitCommand(String cmd) {
1318:                    this .cmd = cmd;
1319:                }
1320:
1321:                @Override
1322:                public CharSequence execute(SQLCommand command) {
1323:                    hide(); // quit
1324:                    return "Application terminated.";
1325:                }
1326:
1327:                @Override
1328:                public CharSequence getHelp() {
1329:                    return "Quit(exit) the application.";
1330:                }
1331:
1332:                @Override
1333:                public CharSequence getCommandString() {
1334:                    return cmd;
1335:                }
1336:
1337:                /**
1338:                 * Returns some tab completion info for the specified command.
1339:                 * @param commandInfo the command lines
1340:                 * @param commandPoint the cursor position
1341:                 * @return some tab completion info for the specified command.
1342:                 */
1343:                @Override
1344:                public TabCompletionInfo getTabCompletionInfo(
1345:                        SQLCommand command, Point commandPoint) {
1346:                    return null;
1347:                }
1348:
1349:                @Override
1350:                public boolean abort() {
1351:                    return false;// not implemented
1352:                }
1353:
1354:                @Override
1355:                public boolean backgroundProcessSupported() {
1356:                    return false;
1357:                }
1358:            }
1359:
1360:            /**
1361:             * Provide help to the user.
1362:             */
1363:            private class HelpCommand implements  Command {
1364:                @Override
1365:                public CharSequence execute(SQLCommand sqlCommand) {
1366:                    // the execution of help consists of:
1367:                    // 1. is general help..
1368:                    // 2. is detailed help about a specific command
1369:                    // 3. help -k something --> search help for a specific keyword
1370:                    String command = sqlCommand.getCommandString().trim();
1371:                    String cmdString = command.substring("help".length())
1372:                            .trim();
1373:                    if (cmdString.endsWith(";")) {
1374:                        cmdString = cmdString.substring(0,
1375:                                cmdString.length() - 1);
1376:                    }
1377:                    List<CharSequence> availableCommands = new ArrayList<CharSequence>();
1378:                    if (cmdString.length() > 0) {
1379:                        if (cmdString.startsWith("-k")) {
1380:                            String keyword = cmdString.subSequence(
1381:                                    cmdString.indexOf(" "), cmdString.length())
1382:                                    .toString().trim();
1383:                            StringBuilder returnValue = new StringBuilder();
1384:                            Iterator<Command> iCommands = commands
1385:                                    .getCommands().iterator();
1386:                            while (iCommands.hasNext()) {
1387:                                Command cmd = iCommands.next();
1388:                                if (cmd.getHelp().toString().indexOf(keyword) >= 0
1389:                                        || cmd.getCommandString().toString()
1390:                                                .indexOf(keyword) >= 0) {
1391:                                    if (returnValue.length() == 0) {
1392:                                        returnValue
1393:                                                .append("See the following commands for more details:\n");
1394:                                    }
1395:                                    returnValue.append("  ");
1396:                                    returnValue.append(cmd.getCommandString());
1397:                                    returnValue.append("\n");
1398:                                }
1399:                            }
1400:                            if (returnValue.length() == 0) {
1401:                                return "Don't know what you mean by '"
1402:                                        + keyword + "'";
1403:                            }
1404:                            return returnValue;
1405:                        } else {
1406:                            Iterator<Command> iCommands = commands
1407:                                    .getCommands().iterator();
1408:                            while (iCommands.hasNext()) {
1409:                                Command cmd = iCommands.next();
1410:                                if (cmd.getCommandString().equals(cmdString)) {
1411:                                    return cmd.getCommandString()
1412:                                            + ":  "
1413:                                            + cmd
1414:                                                    .getHelp()
1415:                                                    .toString()
1416:                                                    .replaceAll(
1417:                                                            "\n",
1418:                                                            "\n"
1419:                                                                    + emptyLine
1420:                                                                            .substring(
1421:                                                                                    0,
1422:                                                                                    cmd
1423:                                                                                            .getCommandString()
1424:                                                                                            .length() + 3));
1425:                                }
1426:                            }
1427:                        }
1428:                        return "Unkown command '" + cmdString + "'";
1429:                    }
1430:                    // default print all commands
1431:                    // TODO iterate
1432:                    StringBuilder returnValue = new StringBuilder();
1433:                    returnValue.append("Available key mappings:\n");
1434:                    int max = 0;
1435:                    Iterator<KeyAction> iKeyActions = actionKeys.values()
1436:                            .iterator();
1437:                    while (iKeyActions.hasNext()) {
1438:                        max = Math.max(max, iKeyActions.next().getHelp()
1439:                                .toString().indexOf('\t'));
1440:                    }
1441:                    iKeyActions = actionKeys.values().iterator();
1442:                    while (iKeyActions.hasNext()) {
1443:                        returnValue.append("    ");
1444:                        //returnValue.append(iKeyActions.next().getHelp());
1445:                        String help = iKeyActions.next().getHelp().toString();
1446:                        int index = help.indexOf('\t');
1447:                        returnValue.append(help.substring(0, index));
1448:                        for (int i = index; i < max; i++) {
1449:                            returnValue.append(' ');
1450:                        }
1451:                        returnValue.append(help.substring(index));
1452:                        returnValue.append('\n');
1453:                    }
1454:                    returnValue.append("\n\nAvailable commands:\n");
1455:                    Iterator<Command> iCommands = commands.getCommands()
1456:                            .iterator();
1457:                    while (iCommands.hasNext()) {
1458:                        Command cmd = iCommands.next();
1459:                        availableCommands.add(cmd.getCommandString());
1460:                    }
1461:                    returnValue.append(toColumns(availableCommands));
1462:                    String helpHeader = "\nHelp for SQLShell client "
1463:                            + SQLProperties.getProperty(
1464:                                    SQLProperties.PropertyName.VERSION,
1465:                                    "SVN Snapshot")
1466:                            + "\n"
1467:                            + "Here you find a list of available commands. "
1468:                            + "To get more information about a specific command enter:\n"
1469:                            + "  help command (for example 'help help')\n\n"
1470:                            + "If the list is not sufficient enough you could try searching help using:\n"
1471:                            + "  help -k searchstring (for example help -k column)\n"
1472:                            + "This results in a list of commands matching the searchstring\n\n";
1473:                    returnValue.insert(0, helpHeader);
1474:                    return returnValue;
1475:                }
1476:
1477:                @Override
1478:                public CharSequence getCommandString() {
1479:                    return "help";
1480:                }
1481:
1482:                /**
1483:                 * Returns some tab completion info for the specified command.
1484:                 * @param commandInfo the command lines
1485:                 * @param commandPoint the cursor position
1486:                 * @return some tab completion info for the specified command.
1487:                 */
1488:                @Override
1489:                public TabCompletionInfo getTabCompletionInfo(
1490:                        SQLCommand command, Point commandPoint) {
1491:                    return null;
1492:                }
1493:
1494:                @Override
1495:                public CharSequence getHelp() {
1496:                    return "this command. Please use 'help' to get a list of available commands you can use.";
1497:                }
1498:
1499:                @Override
1500:                public boolean abort() {
1501:                    return false;// not implemented
1502:                }
1503:
1504:                @Override
1505:                public boolean backgroundProcessSupported() {
1506:                    return false;
1507:                }
1508:            }
1509:
1510:            /**
1511:             * Convert '~/' to the username dir.
1512:             * @param fileName the filename to convert
1513:             * @return the converted filename
1514:             */
1515:            private static String toFileName(String fileName) {
1516:                if (fileName.startsWith("~/")) {
1517:                    return System.getProperty("user.home")
1518:                            + fileName.substring(1);
1519:                }
1520:                return fileName;
1521:            }
1522:
1523:            /**
1524:             * Writes in/output to a file.
1525:             */
1526:            private class SpoolCommand implements  Command {
1527:                private String fileName;
1528:
1529:                @Override
1530:                public CharSequence execute(SQLCommand cmd) {
1531:                    String command = cmd.getCommandString();
1532:                    String nextPart = command.substring("spool".length())
1533:                            .trim();
1534:                    if (nextPart.equalsIgnoreCase("off")) {
1535:                        if (spoolWriter != null) {
1536:                            try {
1537:                                spoolWriter.close();
1538:                            } catch (Exception e) {/*ignore*/
1539:                            }
1540:                            spoolWriter = null;
1541:                            return "Spool closed.";
1542:                        } else {
1543:                            return "No spool to close.";
1544:                        }
1545:                    } else {
1546:                        try {
1547:                            File f = new File(toFileName(nextPart.trim()));
1548:                            fileName = f.getAbsolutePath();
1549:                            if ((f.exists() && !f.canWrite())
1550:                                    || (!f.exists() && !f.createNewFile())) {
1551:                                throw new IllegalStateException(
1552:                                        "Failed to create spool to file: '"
1553:                                                + fileName + "'");
1554:                            }
1555:                            spoolWriter = new FileWriter(fileName);
1556:                        } catch (IOException e) {
1557:                            throw new IllegalStateException(
1558:                                    "Failed to create spool (" + fileName
1559:                                            + "): " + e.toString(), e);
1560:                        }
1561:                        return "Spool to " + fileName + " created.";
1562:                    }
1563:                }
1564:
1565:                @Override
1566:                public CharSequence getCommandString() {
1567:                    return "spool";
1568:                }
1569:
1570:                /**
1571:                 * Returns some tab completion info for the specified command.
1572:                 * @param commandInfo the command lines
1573:                 * @param commandPoint the cursor position
1574:                 * @return some tab completion info for the specified command.
1575:                 */
1576:                @Override
1577:                public TabCompletionInfo getTabCompletionInfo(
1578:                        SQLCommand command, Point commandPoint) {
1579:                    return null;
1580:                }
1581:
1582:                @Override
1583:                public CharSequence getHelp() {
1584:                    return "filename: Spool all output and queries to the specified file\n"
1585:                            + "off     : Stop spooling data to the file.\n"
1586:                            + "Current status:"
1587:                            + (spoolWriter != null ? "on, writing to '"
1588:                                    + fileName + "'" : "off");
1589:                }
1590:
1591:                @Override
1592:                public boolean abort() {
1593:                    return false;// not implemented
1594:                }
1595:
1596:                @Override
1597:                public boolean backgroundProcessSupported() {
1598:                    return false;
1599:                }
1600:            }
1601:
1602:            private class ExecuteBatchCommand implements  Command {
1603:                private boolean cancelled;
1604:                private Command currentCommand;
1605:
1606:                @Override
1607:                public CharSequence execute(SQLCommand sqlCommand) {
1608:                    cancelled = false;
1609:                    currentCommand = null;
1610:                    String command = sqlCommand.getCommandString();
1611:                    // read file from file system and execute
1612:                    FileInputStream fin = null;
1613:                    try {
1614:                        fin = new FileInputStream(toFileName(command
1615:                                .substring(1)));
1616:                        output("Reading file: "
1617:                                + toFileName(command.substring(1)));
1618:                        BufferedReader reader = new BufferedReader(
1619:                                new InputStreamReader(fin));
1620:                        StringBuilder cmd = new StringBuilder();
1621:                        String line;
1622:                        while (((line = reader.readLine()) != null)) {
1623:                            if (cancelled) {
1624:                                return "Aborted";
1625:                            }
1626:                            if (line.startsWith("--")) {
1627:                                continue;
1628:                            }
1629:                            cmd.append(line);
1630:                            if (line.endsWith(";")) {
1631:                                // Exec cmd
1632:                                String commandString = cmd.toString();
1633:                                currentCommand = createCommand(commandString);
1634:                                output(commandString);
1635:                                output(currentCommand.execute(new InputCommand(
1636:                                        commandString)));
1637:                                cmd = new StringBuilder();
1638:                                new Thread() {
1639:                                    public void run() {
1640:                                        paint();
1641:                                    }
1642:                                }.start();
1643:                            }
1644:                        }
1645:                    } catch (IOException e) {
1646:                        error(e);
1647:                    } finally {
1648:                        if (fin != null)
1649:                            try {
1650:                                fin.close();
1651:                            } catch (Exception e) {/*ignore*/
1652:                            }
1653:                        if (cancelled) {
1654:                            return "Execution of file '"
1655:                                    + toFileName(command.substring(1))
1656:                                    + "' aborted....";
1657:                        }
1658:                        return "File '" + toFileName(command.substring(1))
1659:                                + "' executed successfully.";
1660:                    }
1661:                }
1662:
1663:                @Override
1664:                public CharSequence getCommandString() {
1665:                    return "@";
1666:                }
1667:
1668:                /**
1669:                 * Returns some tab completion info for the specified command.
1670:                 * @param commandInfo the command lines
1671:                 * @param commandPoint the cursor position
1672:                 * @return some tab completion info for the specified command.
1673:                 */
1674:                @Override
1675:                public TabCompletionInfo getTabCompletionInfo(
1676:                        SQLCommand command, Point commandPoint) {
1677:                    String fileName = command.getCommandString().substring(1)
1678:                            .trim(); // cutoff '@'
1679:                    String dirName;
1680:                    if (fileName.equals("")) {
1681:                        fileName = ".";
1682:                        dirName = ".";
1683:                    } else {
1684:                        fileName = toFileName(fileName);
1685:                        if (fileName.indexOf('/') >= 0) {
1686:                            File file = new File(fileName);
1687:                            if (file.isDirectory()) {
1688:                                fileName = "";
1689:                                dirName = file.getAbsolutePath() + "/";
1690:                            } else {
1691:                                fileName = file.getName();
1692:                                dirName = file.getParent();
1693:                            }
1694:                        } else {
1695:                            dirName = ".";
1696:                        }
1697:                    }
1698:                    return new TabCompletionInfo(
1699:                            TabCompletionInfo.MatchType.UNKNOWN, Arrays
1700:                                    .asList(new File(dirName).list()), fileName);
1701:                }
1702:
1703:                @Override
1704:                public CharSequence getHelp() {
1705:                    return "Specify filename to execute a 'batch' command.\n"
1706:                            + "For example '@mystatements.sql' executes all statements part of the mystatements.sql file in the current directory."
1707:                            + "Note that all statements must be terminated with ';' (sql statements as well as connect statements or spool)";
1708:                }
1709:
1710:                @Override
1711:                public boolean abort() {
1712:                    cancelled = true;
1713:                    if (currentCommand != null) {
1714:                        currentCommand.abort();
1715:                    }
1716:                    return true;
1717:                }
1718:
1719:                @Override
1720:                public boolean backgroundProcessSupported() {
1721:                    return true;
1722:                }
1723:            }
1724:
1725:            /**
1726:             * Command class to execute a 'custom command'.
1727:             * this makes it possible to have 'automated' commands executed.
1728:             * E.g.:
1729:             *  executeCommand(new InputCommand("connect"));
1730:             * will eventually execute the Connect command. 
1731:             */
1732:            private static class InputCommand extends SQLCommand {
1733:                private StringBuilder command;
1734:
1735:                public InputCommand(String command) {
1736:                    this .command = new StringBuilder(command);
1737:                }
1738:
1739:                public InputCommand(StringBuilder command) {
1740:                    this .command = command;
1741:                }
1742:
1743:                @Override
1744:                public String getUntrimmedCommandString() {
1745:                    return command.toString();
1746:                }
1747:
1748:                @Override
1749:                public List<StringBuilder> getEditableLines() {
1750:                    return Arrays.asList(new StringBuilder[] { command });
1751:                }
1752:
1753:                @Override
1754:                public List<? extends CharSequence> getLines() {
1755:                    return Arrays.asList(new StringBuilder[] { command });
1756:                }
1757:            }
1758:
1759:            private abstract class CommandThread extends Thread {
1760:                private Command cmd;
1761:
1762:                public CommandThread(Command cmd) {
1763:                    this .cmd = cmd;
1764:                }
1765:
1766:                public final void run() {
1767:                    showPrompt = false;
1768:                    try {
1769:                        execute();
1770:                    } finally {
1771:                        showPrompt = true;
1772:                        paint();
1773:                    }
1774:                }
1775:
1776:                abstract void execute();
1777:
1778:                Command getCommand() {
1779:                    return cmd;
1780:                }
1781:            }
1782:
1783:            private class QueryCommand implements  Command {
1784:
1785:                /**
1786:                 * Executor for SQL Statements
1787:                 */
1788:                private StatementExecutor statementExecutor;
1789:
1790:                @Override
1791:                public CharSequence execute(SQLCommand cmd) {
1792:                    try {
1793:                        String command = cmd.getCommandString();
1794:                        if (command.length() > "select".length()
1795:                                && "select".equalsIgnoreCase(command
1796:                                        .subSequence(0, "create".length())
1797:                                        .toString())) {
1798:                            return DBConnector.getInstance().getQueryExecutor()
1799:                                    .executeQuery(command);
1800:                        }
1801:                        if (statementExecutor == null) {
1802:                            statementExecutor = new StatementExecutor();
1803:                        }
1804:                        return statementExecutor.execute(command);
1805:                    } catch (SQLException e) {
1806:                        error(e);
1807:                        return "";
1808:                    } catch (IllegalStateException e) {
1809:                        error(e);
1810:                        return "";
1811:                    }
1812:                }
1813:
1814:                @Override
1815:                public CharSequence getCommandString() {
1816:                    return "";
1817:                }
1818:
1819:                @Override
1820:                public TabCompletionInfo getTabCompletionInfo(
1821:                        SQLCommand commandInfo, Point commandPoint) {
1822:                    // TODO call SQLUTil..
1823:                    return null;
1824:                }
1825:
1826:                @Override
1827:                public CharSequence getHelp() {
1828:                    return "";
1829:                }
1830:
1831:                @Override
1832:                public boolean abort() {
1833:                    //DBConnector.getInstance().getStatement().cancel();
1834:                    output(DBConnector.getInstance().getQueryExecutor()
1835:                            .cancel());
1836:                    return true;
1837:                }
1838:
1839:                @Override
1840:                public boolean backgroundProcessSupported() {
1841:                    return true;
1842:                }
1843:
1844:            }
1845:
1846:            private interface KeyAction {
1847:                void execute();
1848:
1849:                CharSequence getHelp();
1850:            }
1851:
1852:            public static void main(String[] args) {
1853:                SQLShell shell = new SQLShell();
1854:                shell.show();
1855:
1856:                //Interpret first argument as a connect argument
1857:                if (args.length > 0) {
1858:                    shell
1859:                            .executeCommand(new InputCommand("connect "
1860:                                    + args[0]));
1861:                }
1862:            }
1863:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.