View Javadoc

1   /*
2    * Copyright (c) 2002-2012, the original author or authors.
3    *
4    * This software is distributable under the BSD license. See the terms of the
5    * BSD license in the documentation provided with this software.
6    *
7    * http://www.opensource.org/licenses/bsd-license.php
8    */
9   package jline;
10  
11  import java.text.MessageFormat;
12  import java.util.HashMap;
13  import java.util.Map;
14  
15  import jline.internal.Configuration;
16  import jline.internal.Log;
17  import jline.internal.Preconditions;
18  
19  import static jline.internal.Preconditions.checkNotNull;
20  
21  /**
22   * Creates terminal instances.
23   *
24   * @author <a href="mailto:jason@planet57.com">Jason Dillon</a>
25   * @since 2.0
26   */
27  public class TerminalFactory
28  {
29      public static final String JLINE_TERMINAL = "jline.terminal";
30  
31      public static final String AUTO = "auto";
32  
33      public static final String UNIX = "unix";
34  
35      public static final String WIN = "win";
36  
37      public static final String WINDOWS = "windows";
38  
39      public static final String NONE = "none";
40  
41      public static final String OFF = "off";
42  
43      public static final String FALSE = "false";
44  
45      private static Terminal term = null;
46  
47      public static synchronized Terminal create() {
48          if (Log.TRACE) {
49              //noinspection ThrowableInstanceNeverThrown
50              Log.trace(new Throwable("CREATE MARKER"));
51          }
52  
53          String type = Configuration.getString(JLINE_TERMINAL, AUTO);
54          if ("dumb".equals(System.getenv("TERM"))) {
55              type = "none";
56              Log.debug("$TERM=dumb; setting type=", type);
57          }
58  
59          Log.debug("Creating terminal; type=", type);
60  
61          Terminal t;
62          try {
63              String tmp = type.toLowerCase();
64  
65              if (tmp.equals(UNIX)) {
66                  t = getFlavor(Flavor.UNIX);
67              }
68              else if (tmp.equals(WIN) | tmp.equals(WINDOWS)) {
69                  t = getFlavor(Flavor.WINDOWS);
70              }
71              else if (tmp.equals(NONE) || tmp.equals(OFF) || tmp.equals(FALSE)) {
72                  t = new UnsupportedTerminal();
73              }
74              else {
75                  if (tmp.equals(AUTO)) {
76                      String os = Configuration.getOsName();
77                      Flavor flavor = Flavor.UNIX;
78                      if (os.contains(WINDOWS)) {
79                          flavor = Flavor.WINDOWS;
80                      }
81                      t = getFlavor(flavor);
82                  }
83                  else {
84                      try {
85                          t = (Terminal) Thread.currentThread().getContextClassLoader().loadClass(type).newInstance();
86                      }
87                      catch (Exception e) {
88                          throw new IllegalArgumentException(MessageFormat.format("Invalid terminal type: {0}", type), e);
89                      }
90                  }
91              }
92          }
93          catch (Exception e) {
94              Log.error("Failed to construct terminal; falling back to unsupported", e);
95              t = new UnsupportedTerminal();
96          }
97  
98          Log.debug("Created Terminal: ", t);
99  
100         try {
101             t.init();
102         }
103         catch (Throwable e) {
104             Log.error("Terminal initialization failed; falling back to unsupported", e);
105             return new UnsupportedTerminal();
106         }
107 
108         return t;
109     }
110 
111     public static synchronized void reset() {
112         term = null;
113     }
114 
115     public static synchronized void resetIf(final Terminal t) {
116         if(t == term) {
117             reset();
118         }
119     }
120 
121     public static enum Type
122     {
123         AUTO,
124         WINDOWS,
125         UNIX,
126         NONE
127     }
128 
129     public static synchronized void configure(final String type) {
130         checkNotNull(type);
131         System.setProperty(JLINE_TERMINAL, type);
132     }
133 
134     public static synchronized void configure(final Type type) {
135         checkNotNull(type);
136         configure(type.name().toLowerCase());
137     }
138 
139     //
140     // Flavor Support
141     //
142 
143     public static enum Flavor
144     {
145         WINDOWS,
146         UNIX
147     }
148 
149     private static final Map<Flavor, Class<? extends Terminal>> FLAVORS = new HashMap<Flavor, Class<? extends Terminal>>();
150 
151     static {
152         registerFlavor(Flavor.WINDOWS, AnsiWindowsTerminal.class);
153         registerFlavor(Flavor.UNIX, UnixTerminal.class);
154     }
155 
156     public static synchronized Terminal get() {
157         if (term == null) {
158             term = create();
159         }
160         return term;
161     }
162 
163     public static Terminal getFlavor(final Flavor flavor) throws Exception {
164         Class<? extends Terminal> type = FLAVORS.get(flavor);
165         if (type != null) {
166             return type.newInstance();
167         }
168 
169         throw new InternalError();
170     }
171 
172     public static void registerFlavor(final Flavor flavor, final Class<? extends Terminal> type) {
173         FLAVORS.put(flavor, type);
174     }
175 
176 }