001    /*
002     * Copyright (c) 2002-2007, Marc Prud'hommeaux. All rights reserved.
003     *
004     * This software is distributable under the BSD license. See the terms of the
005     * BSD license in the documentation provided with this software.
006     */
007    package jline;
008    
009    import java.io.*;
010    
011    //import com.sun.jmx.snmp.ThreadContext;
012    
013    /**
014     *  Representation of the input terminal for a platform. Handles
015     *  any initialization that the platform may need to perform
016     *  in order to allow the {@link ConsoleReader} to correctly handle
017     *  input.
018     *
019     *  @author  <a href="mailto:mwp1@cornell.edu">Marc Prud'hommeaux</a>
020     */
021    public abstract class Terminal implements ConsoleOperations {
022        private static Terminal term;
023    
024        /**
025         *  @see #setupTerminal
026         */
027        public static Terminal getTerminal() {
028            return setupTerminal();
029        }
030    
031        /** 
032         *  Reset the current terminal to null. 
033         */
034        public static void resetTerminal() {
035            term = null;
036        }
037    
038        /**
039         *  <p>Configure and return the {@link Terminal} instance for the
040         *  current platform. This will initialize any system settings
041         *  that are required for the console to be able to handle
042         *  input correctly, such as setting tabtop, buffered input, and
043         *  character echo.</p>
044         *
045         *  <p>This class will use the Terminal implementation specified in the
046         *  <em>jline.terminal</em> system property, or, if it is unset, by
047         *  detecting the operating system from the <em>os.name</em>
048         *  system property and instantiating either the
049         *  {@link WindowsTerminalTest} or {@link UnixTerminal}.
050         *
051         *  @see #initializeTerminal
052         */
053        public static synchronized Terminal setupTerminal() {
054            if (term != null) {
055                return term;
056            }
057    
058            final Terminal t;
059    
060            String os = System.getProperty("os.name").toLowerCase();
061            String termProp = System.getProperty("jline.terminal");
062    
063            if ((termProp != null) && (termProp.length() > 0)) {
064                try {
065                    t = (Terminal) Class.forName(termProp).newInstance();
066                } catch (Exception e) {
067                    throw (IllegalArgumentException) new IllegalArgumentException(e
068                        .toString()).fillInStackTrace();
069                }
070            } else if (os.indexOf("windows") != -1) {
071                t = new WindowsTerminal();
072            } else {
073                t = new UnixTerminal();
074            }
075    
076            try {
077                t.initializeTerminal();
078            } catch (Exception e) {
079                e.printStackTrace();
080    
081                return term = new UnsupportedTerminal();
082            }
083    
084            return term = t;
085        }
086    
087        /**
088         *  Returns true if the current console supports ANSI
089         *  codes.
090         */
091        public boolean isANSISupported() {
092            return true;
093        }
094    
095        /**
096         *  Read a single character from the input stream. This might
097         *  enable a terminal implementation to better handle nuances of
098         *  the console.
099         */
100        public int readCharacter(final InputStream in) throws IOException {
101            return in.read();
102        }
103    
104        /**
105         *  Reads a virtual key from the console. Typically, this will
106         *  just be the raw character that was entered, but in some cases,
107         *  multiple input keys will need to be translated into a single
108         *  virtual key.
109         *
110         *  @param  in  the InputStream to read from
111         *  @return  the virtual key (e.g., {@link ConsoleOperations#VK_UP})
112         */
113        public int readVirtualKey(InputStream in) throws IOException {
114            return readCharacter(in);
115        }
116    
117        /**
118         *  Initialize any system settings
119         *  that are required for the console to be able to handle
120         *  input correctly, such as setting tabtop, buffered input, and
121         *  character echo.
122         */
123        public abstract void initializeTerminal() throws Exception;
124    
125        /**
126         *  Returns the current width of the terminal (in characters)
127         */
128        public abstract int getTerminalWidth();
129    
130        /**
131         *  Returns the current height of the terminal (in lines)
132         */
133        public abstract int getTerminalHeight();
134    
135        /**
136         *  Returns true if this terminal is capable of initializing the
137         *  terminal to use jline.
138         */
139        public abstract boolean isSupported();
140    
141        /**
142         *  Returns true if the terminal will echo all characters type.
143         */
144        public abstract boolean getEcho();
145    
146        /**
147         *  Invokes before the console reads a line with the prompt and mask.
148         */
149        public void beforeReadLine(ConsoleReader reader, String prompt,
150                                   Character mask) {
151        }
152    
153        /**
154         *  Invokes after the console reads a line with the prompt and mask.
155         */
156        public void afterReadLine(ConsoleReader reader, String prompt,
157                                  Character mask) {
158        }
159    
160        /**
161         *  Returns false if character echoing is disabled.
162         */
163        public abstract boolean isEchoEnabled();
164    
165    
166        /**
167         *  Enable character echoing. This can be used to re-enable character
168         *  if the ConsoleReader is no longer being used.
169         */
170        public abstract void enableEcho();
171    
172    
173        /**
174         *  Disable character echoing. This can be used to manually re-enable
175         *  character if the ConsoleReader has been disabled.
176         */
177        public abstract void disableEcho();
178    
179        public InputStream getDefaultBindings() {
180            return getClass().getResourceAsStream("keybindings.properties");
181        }
182    }