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 }