Source Code Cross Referenced for ShellChannel.java in  » Net » ssh-web-proxy » com » ericdaugherty » sshwebproxy » 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 » Net » ssh web proxy » com.ericdaugherty.sshwebproxy 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


001:        /******************************************************************************
002:         * $Source: /cvsroot/sshwebproxy/src/java/com/ericdaugherty/sshwebproxy/ShellChannel.java,v $
003:         * $Revision: 1.4 $
004:         * $Author: edaugherty $
005:         * $Date: 2003/12/09 02:52:24 $
006:         ******************************************************************************
007:         * Copyright (c) 2003, Eric Daugherty (http://www.ericdaugherty.com)
008:         * All rights reserved.
009:         *
010:         * Redistribution and use in source and binary forms, with or without
011:         * modification, are permitted provided that the following conditions are met:
012:         *
013:         *     * Redistributions of source code must retain the above copyright notice,
014:         *       this list of conditions and the following disclaimer.
015:         *     * Redistributions in binary form must reproduce the above copyright
016:         *       notice, this list of conditions and the following disclaimer in the
017:         *       documentation and/or other materials provided with the distribution.
018:         *     * Neither the name of the Eric Daugherty nor the names of its
019:         *       contributors may be used to endorse or promote products derived
020:         *       from this software without specific prior written permission.
021:         *
022:         * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
023:         * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
024:         * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
025:         * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
026:         * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
027:         * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
028:         * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
029:         * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
030:         * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
031:         * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
032:         * THE POSSIBILITY OF SUCH DAMAGE.
033:         * *****************************************************************************
034:         * For current versions and more information, please visit:
035:         * http://www.ericdaugherty.com/dev/sshwebproxy
036:         *
037:         * or contact the author at:
038:         * web@ericdaugherty.com
039:         *****************************************************************************/package com.ericdaugherty.sshwebproxy;
040:
041:        import org.apache.commons.logging.LogFactory;
042:        import org.apache.commons.logging.Log;
043:
044:        import java.util.ArrayList;
045:        import java.io.*;
046:
047:        import com.sshtools.j2ssh.session.SessionChannelClient;
048:
049:        /**
050:         * Provide an implementation of the SshChannel for interactive
051:         * shell sessions.
052:         * <p>
053:         * While this is a concrete class that can be instantiated,
054:         * the VT100ShellChannel should be used as the default ShellChannel
055:         * because it provides a more robust shell implementation.  This class
056:         * should be extended by other terminal emulation classes, or instantiated
057:         * directly for a very simple shell interaction.
058:         *
059:         * @author Eric Daugherty
060:         */
061:        public class ShellChannel extends SshChannel implements  SshConstants {
062:
063:            //***************************************************************
064:            // Variables
065:            //***************************************************************
066:
067:            /** The number of columns to display as a screen */
068:            protected int screenWidth = 80;
069:
070:            /** The number of rows to display as a screen */
071:            protected int screenHeight = 24;
072:
073:            /** The total number of rows to store */
074:            private int bufferMaxSize = 1000;
075:
076:            /** The number of milliseconds to pause before reading */
077:            private int readPause = 250;
078:
079:            /** The size of the buffer to read from the server */
080:            private int readBufferSize = 4048;
081:
082:            /** The row that the cursor is currently on */
083:            private int cursorRow = -1;
084:
085:            /** The column that the cursor is currently on */
086:            private int cursorColumn = -1;
087:
088:            /** The Channel for the current Shell Connection */
089:            protected SessionChannelClient sshChannel;
090:
091:            /** The Input Reader for the SSH shell connection. */
092:            private BufferedReader reader;
093:
094:            /** The Output Writer for the SSH shell connection */
095:            private PrintWriter writer;
096:
097:            /** The entire stored buffer. */
098:            private ArrayList buffer;
099:
100:            /** Logger */
101:            private static final Log log = LogFactory
102:                    .getLog(ShellChannel.class);
103:
104:            //***************************************************************
105:            // Constructor
106:            //***************************************************************
107:
108:            /**
109:             * Opens a vt100 terminal session transfer session with the server.
110:             *
111:             * @param sshConnection the connection to use.
112:             * @param sshChannel the SSH API channel.
113:             * @throws SshConnectException thrown if there is any error opening
114:             * the connection.
115:             */
116:            public ShellChannel(SshConnection sshConnection,
117:                    SessionChannelClient sshChannel) throws SshConnectException {
118:                super (CHANNEL_TYPE_SHELL, sshConnection);
119:
120:                this .sshChannel = sshChannel;
121:
122:                // Initialize the channel for a shell session.
123:                try {
124:                    if (!sshChannel.requestPseudoTerminal("vt100",
125:                            getScreenWidth(), getScreenHeight(), 0, 0, "")) {
126:                        log
127:                                .warn("ShellChannel constructor failed, unable to open PseudoTerminal for connection: "
128:                                        + sshConnection.getConnectionInfo());
129:                        throw new SshConnectException(
130:                                "Unable to establish PseudoTerminal for new ShellChannel.");
131:                    } else if (!sshChannel.startShell()) {
132:                        log
133:                                .warn("ShellChannel constructor failed, unable to start shell on new channel for connection: "
134:                                        + sshConnection.getConnectionInfo());
135:                        throw new SshConnectException(
136:                                "Unable to start Shell for new ShellChannel.");
137:                    }
138:
139:                    writer = new PrintWriter(new OutputStreamWriter(sshChannel
140:                            .getOutputStream()));
141:                    reader = new BufferedReader(new InputStreamReader(
142:                            sshChannel.getInputStream()));
143:
144:                    buffer = new ArrayList(bufferMaxSize);
145:                } catch (IOException ioException) {
146:                    log
147:                            .warn(
148:                                    "ShellChannel constructor failed, IOException occured while setting up channel  for connection: "
149:                                            + sshConnection.getConnectionInfo()
150:                                            + ". IOException: " + ioException,
151:                                    ioException);
152:                    throw new SshConnectException(
153:                            "Unable to establish Shell Connection.  IOExeption occured: "
154:                                    + ioException);
155:                }
156:            }
157:
158:            //***************************************************************
159:            // SshChannel Methods
160:            //***************************************************************
161:
162:            /**
163:             * Closes the Reader and Writer after the Channel has been closed.
164:             * This should only be called by the SshConnection
165:             * class and never directly called from this class.
166:             */
167:            public void close() {
168:                // Close Readers and Writers.
169:                if (log.isInfoEnabled())
170:                    log.debug("Closing ShellChannel connected to: "
171:                            + sshConnection.getConnectionInfo());
172:
173:                if (reader != null) {
174:                    try {
175:                        reader.close();
176:                    } catch (IOException ioException) {
177:                        log
178:                                .warn("Error closing BufferedReader for Shell Connection to: "
179:                                        + sshConnection.getConnectionInfo()
180:                                        + ".  IOException: " + ioException);
181:                    }
182:                    reader = null;
183:                }
184:                if (writer != null) {
185:                    writer.close();
186:                    writer = null;
187:                }
188:
189:                // Close the channel if it is open.
190:                if (sshChannel.isOpen()) {
191:                    try {
192:                        sshChannel.close();
193:                    } catch (IOException ioException) {
194:                        log
195:                                .warn("Error closing SessionChannelClient  for Shell Connection to: "
196:                                        + sshConnection.getConnectionInfo()
197:                                        + ".  IOException: " + ioException);
198:                    }
199:                }
200:            }
201:
202:            /**
203:             * Indicates whether this connection is still active.
204:             *
205:             * @return true if this connection is still active.
206:             */
207:            public boolean isConnected() {
208:                return !sshChannel.isClosed();
209:            }
210:
211:            /**
212:             * Returns the page that should be used to display this Channel.
213:             *
214:             * @return
215:             */
216:            public String getPage() {
217:                return PAGE_SHELL_HOME + "?connection="
218:                        + sshConnection.getConnectionInfo() + "&channel="
219:                        + getChannelId();
220:            }
221:
222:            //***************************************************************
223:            // Public Parameter Access
224:            //***************************************************************
225:
226:            /**
227:             * The number of columns to display as a screen
228:             */
229:            public int getScreenWidth() {
230:                return screenWidth;
231:            }
232:
233:            /**
234:             * The number of rows to display as a screen
235:             */
236:            public int getScreenHeight() {
237:                return screenHeight;
238:            }
239:
240:            /**
241:             * The total number of rows to store in the buffer.
242:             *
243:             * @return number of rows to store.
244:             */
245:            public int getBufferMaxSize() {
246:                return bufferMaxSize;
247:            }
248:
249:            /**
250:             * The number of milliseconds to pause before reading
251:             * data.  This helps reduce the number of read requests
252:             * after a write request.
253:             *
254:             * @return the number of milliseconds to pause.
255:             */
256:            public int getReadPause() {
257:                return readPause;
258:            }
259:
260:            /**
261:             * The maximum amount of data to read from the server
262:             * for each read() call.
263:             *
264:             * @return the max read buffer size.
265:             */
266:            public int getReadBufferSize() {
267:                return readBufferSize;
268:            }
269:
270:            /**
271:             * The index of the row the cursor is on.  The cursor location
272:             * is assumed to be after that last character from the server.
273:             *
274:             * @return the row index of the cursor.
275:             */
276:            public int getCursorRow() {
277:                return cursorRow;
278:            }
279:
280:            /**
281:             * The index of the row the cursor is on.  The cursor location
282:             * is assumed to be after that last character from the server.
283:             *
284:             * @return the column index of the cursor.
285:             */
286:            public int getCursorColumn() {
287:                return cursorColumn;
288:            }
289:
290:            //***************************************************************
291:            // Public Data Manipulation
292:            //***************************************************************
293:
294:            /**
295:             * Performs a read of the input data and fills the buffer.
296:             * This should be called before getScreen or getBuffer.
297:             */
298:            public void read() {
299:                if (log.isDebugEnabled())
300:                    log.debug("read called for ShellConnection to: "
301:                            + sshConnection.getConnectionInfo());
302:
303:                // We want to read even if the channel has been closed, because
304:                // the BufferedReader may have buffered some input, so do the
305:                // check after this read.  But if the reader is null, just
306:                // ignore the call.
307:                if (reader == null) {
308:                    log.warn("read called on null reader.  Ignoring.");
309:                    return;
310:                }
311:
312:                // Read from the server
313:                try {
314:                    // Initialize the input buffer.
315:                    char[] inputBuffer = new char[readBufferSize];
316:                    String input = null;
317:
318:                    // Sleep for the read pause.  This allows the server
319:                    // to send us the 'full' data.  If we don't sleep,
320:                    // the user may just have to do a refresh right away
321:                    // anyway.
322:                    try {
323:                        Thread.sleep(getReadPause());
324:                    } catch (InterruptedException e) {
325:                        log.warn("Read Pause interrupted in read().");
326:                    }
327:
328:                    // If there is data ready, go ahead and read it.
329:                    if (reader.ready()) {
330:                        // read the data and run it through the processor.
331:                        int count = reader.read(inputBuffer);
332:                        input = process(inputBuffer, count);
333:                        if (log.isDebugEnabled())
334:                            log.debug("Read " + count
335:                                    + " characters from server.");
336:
337:                        fillBuffer(input);
338:
339:                        // Check to see if the channel was closed.
340:                        if (!isConnected()) {
341:                            if (!reader.ready()) {
342:                                if (log.isDebugEnabled())
343:                                    log.debug("ShellChannel for connecton: "
344:                                            + sshConnection.getConnectionInfo()
345:                                            + " Closed, closing streams.");
346:
347:                                // Notify the sshConnection that this channel is closed.
348:                                sshConnection.closeChannel(this );
349:                            } else {
350:                                if (log.isDebugEnabled())
351:                                    log
352:                                            .debug("Connection Closed but there is more data to be read.");
353:                            }
354:                        }
355:                    } else {
356:                        log.debug("ShellChannel for connection: "
357:                                + sshConnection.getConnectionInfo()
358:                                + " has no data to read.");
359:                    }
360:                } catch (IOException ioException) {
361:                    log.error("Error reading ShellChannel for connection: "
362:                            + sshConnection.getConnectionInfo()
363:                            + ".  IOException while in read(): " + ioException,
364:                            ioException);
365:                }
366:            }
367:
368:            /**
369:             * Writes the data to the SSH server and sends a newline charecter
370:             * "\n" if the sendNewLine boolean is true.
371:             *
372:             * @param data the data to write.
373:             * @param sendNewLine true if a newline should be sent.
374:             */
375:            public void write(String data, boolean sendNewLine) {
376:                // Don't write if the channel is closed.
377:                if (!isConnected()) {
378:                    log
379:                            .info("Write call on closed ShellChannel for connection: "
380:                                    + sshConnection.getConnectionInfo()
381:                                    + ".  Ignoring.");
382:                    return;
383:                }
384:
385:                // Verify the writer is not null.
386:                if (writer == null) {
387:                    log
388:                            .info("Write call on closed ShellChannel Writer for connection: "
389:                                    + sshConnection.getConnectionInfo()
390:                                    + ".  Ignoring.");
391:                    return;
392:                }
393:
394:                // Encode the data for output.  Convert any control characters to
395:                // the correct char value.
396:                char[] output = encodeOutput(data);
397:
398:                if (log.isDebugEnabled())
399:                    log.debug("Wrote " + output.length
400:                            + " characters to ShellChannel for connection: "
401:                            + sshConnection.getConnectionInfo());
402:
403:                // Write the output, and send a new line if requested.
404:                writer.print(output);
405:                if (sendNewLine) {
406:                    writer.print("\n");
407:                }
408:                writer.flush();
409:            }
410:
411:            /**
412:             * Adds the data that was read to the buffer.
413:             *
414:             * @param input the processed data read from the server
415:             */
416:            public void fillBuffer(String input) {
417:                // Add data to the buffer.
418:                String[] lines = input.split("\r\n");
419:                int startIndex = 0;
420:
421:                // Append the first line on the end of the last line.
422:                if (buffer.size() > 0 && lines.length > 0) {
423:                    int lastIndex = buffer.size() - 1;
424:                    buffer.set(lastIndex, ((String) buffer.get(lastIndex))
425:                            + lines[0]);
426:                    startIndex = 1;
427:                }
428:
429:                // Add the rest of the new lines.
430:                for (int index = startIndex; index < lines.length; index++) {
431:                    buffer.add(lines[index]);
432:                }
433:
434:                // Append a new empty line if the last line ended with a line feed.
435:                if (input.lastIndexOf("\r\n") == input.length() - 2) {
436:                    buffer.add("");
437:                }
438:
439:                // Remove any extra rows from the begining of the buffer.
440:                int currentBufferSize = buffer.size();
441:                if (currentBufferSize > bufferMaxSize) {
442:                    int trimCount = currentBufferSize - bufferMaxSize;
443:                    if (log.isDebugEnabled())
444:                        log.debug("Removing " + trimCount
445:                                + " rows from the buffer.");
446:                    for (int index = 0; index < trimCount; index++) {
447:                        buffer.remove(0);
448:                    }
449:                }
450:            }
451:
452:            /**
453:             * Returns a String array of the currently visible
454:             * rows.  The number of rows returned will always match
455:             * the Screen Size.
456:             *
457:             * @return Array of Strings that represent the current data on the screen.
458:             */
459:            public String[] getScreen() {
460:                String[] screen = new String[screenHeight];
461:
462:                int currentBufferSize = buffer.size();
463:
464:                if (currentBufferSize <= screenHeight) {
465:                    int index;
466:                    // Fill the screen array with the buffer.
467:                    for (index = 0; index < currentBufferSize; index++) {
468:                        screen[index] = (String) buffer.get(index);
469:                    }
470:                    // Fill out any remaining rows.
471:                    for (; index < screenHeight; index++) {
472:                        screen[index] = "";
473:                    }
474:
475:                    cursorRow = currentBufferSize - 1;
476:                    cursorColumn = -1;
477:                } else {
478:                    int bufferIndex = currentBufferSize - screenHeight;
479:                    int screenIndex = 0;
480:                    for (; bufferIndex < currentBufferSize; bufferIndex++) {
481:                        screen[screenIndex++] = (String) buffer
482:                                .get(bufferIndex);
483:                    }
484:
485:                    cursorRow = screenHeight - 1;
486:                    cursorColumn = -1;
487:                }
488:
489:                return screen;
490:            }
491:
492:            /**
493:             * Returns a String array of the entire buffer.
494:             * rows.
495:             *
496:             * @return Array of Strings that represent the entire buffer.
497:             */
498:            public String[] getBuffer() {
499:                int currentBufferSize = buffer.size();
500:                String[] bufferArray = new String[currentBufferSize];
501:
502:                for (int index = 0; index < currentBufferSize; index++) {
503:                    bufferArray[index] = (String) buffer.get(index);
504:                }
505:
506:                return bufferArray;
507:            }
508:
509:            /**
510:             * Process the incoming request into a string.
511:             * @return
512:             */
513:            protected String process(char[] inputBuffer, int count) {
514:                return String.valueOf(inputBuffer, 0, count);
515:            }
516:
517:            /**
518:             * Parse the data to write to the server for control characters.
519:             *
520:             * @param input the data read from the client.
521:             * @return a char array to write to the server.
522:             */
523:            private char[] encodeOutput(String input) {
524:                char[] translateBuffer = new char[input.length()];
525:                int originalCount = input.length();
526:                int outputCount = 0;
527:                boolean ctrlPressed = false;
528:
529:                for (int index = 0; index < originalCount; index++) {
530:                    // Check if the last key was a control key.
531:                    if (ctrlPressed == true) {
532:                        ctrlPressed = false;
533:                        String shiftedKey = String.valueOf(input.charAt(index));
534:                        shiftedKey = shiftedKey.toUpperCase();
535:                        char newChar = (char) (shiftedKey.charAt(0) - 64);
536:                        translateBuffer[outputCount++] = newChar;
537:                    }
538:                    // Encode control characters.
539:                    else if (input.charAt(index) == '#') {
540:                        // Make sure we have a full sequence.
541:                        if (input.length() < (index + 3)) {
542:                            log
543:                                    .error("Invalid input data.  Failed encoding.  There must be 2 characters after the # character.");
544:                            return new char[0];
545:                        }
546:
547:                        try {
548:                            String charNumber = input.substring(index + 1,
549:                                    index + 3);
550:                            int charValue = Integer.parseInt(charNumber, 16);
551:                            if (charValue == -1) {
552:                                ctrlPressed = true;
553:                            }
554:                            if (log.isDebugEnabled())
555:                                log.debug("Encoded #" + charNumber
556:                                        + " to decimal: " + charValue);
557:                            index = index + 2;
558:                            translateBuffer[outputCount++] = (char) charValue;
559:                        } catch (NumberFormatException numberFormatException) {
560:                            log
561:                                    .error("Invalid input data.  failed encoding.  The control character did not contain a valid hex value.");
562:                            return new char[0];
563:                        }
564:                    } else {
565:                        translateBuffer[outputCount++] = input.charAt(index);
566:                    }
567:                }
568:
569:                char[] outputBuffer = new char[outputCount];
570:                for (int index = 0; index < outputCount; index++) {
571:                    outputBuffer[index] = translateBuffer[index];
572:                }
573:
574:                return outputBuffer;
575:            }
576:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.