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 jdk.internal.jline; 10 11 import java.text.MessageFormat; 12 import java.util.HashMap; 13 import java.util.Map; 14 15 import jdk.internal.jline.internal.Configuration; 16 import jdk.internal.jline.internal.Log; 17 import jdk.internal.jline.internal.Preconditions; 18 import static jdk.internal.jline.internal.Preconditions.checkNotNull; 19 20 /** 21 * Creates terminal instances. 22 * 23 * @author <a href="mailto:jason@planet57.com">Jason Dillon</a> 24 * @since 2.0 25 */ 26 public class TerminalFactory 27 { 28 public static final String JLINE_TERMINAL = "jline.terminal"; 29 30 public static final String AUTO = "auto"; 31 32 public static final String UNIX = "unix"; 33 34 public static final String WIN = "win"; 35 36 public static final String WINDOWS = "windows"; 37 38 public static final String NONE = "none"; 39 40 public static final String OFF = "off"; 41 42 public static final String FALSE = "false"; 43 44 private static Terminal term = null; 45 46 public static synchronized Terminal create() { 47 if (Log.TRACE) { 48 //noinspection ThrowableInstanceNeverThrown 49 Log.trace(new Throwable("CREATE MARKER")); 50 } 51 52 String type = Configuration.getString(JLINE_TERMINAL, AUTO); 53 if ("dumb".equals(System.getenv("TERM"))) { 54 type = "none"; 55 Log.debug("$TERM=dumb; setting type=", type); 56 } 57 58 Log.debug("Creating terminal; type=", type); 59 60 Terminal t; 61 try { 62 String tmp = type.toLowerCase(); 63 64 if (tmp.equals(UNIX)) { 65 t = getFlavor(Flavor.UNIX); 66 } 67 else if (tmp.equals(WIN) | tmp.equals(WINDOWS)) { 68 t = getFlavor(Flavor.WINDOWS); 69 } 70 else if (tmp.equals(NONE) || tmp.equals(OFF) || tmp.equals(FALSE)) { 71 t = new UnsupportedTerminal(); 72 } 73 else { 74 if (tmp.equals(AUTO)) { 75 String os = Configuration.getOsName(); 76 Flavor flavor = Flavor.UNIX; 77 if (os.contains(WINDOWS)) { 78 flavor = Flavor.WINDOWS; 79 } 80 t = getFlavor(flavor); 81 } 82 else { 83 try { 84 t = (Terminal) Thread.currentThread().getContextClassLoader().loadClass(type).newInstance(); 85 } 86 catch (Exception e) { 87 throw new IllegalArgumentException(MessageFormat.format("Invalid terminal type: {0}", type), e); 88 } 89 } 90 } 91 } 92 catch (Exception e) { 93 Log.error("Failed to construct terminal; falling back to unsupported", e); 94 t = new UnsupportedTerminal(); 95 } 96 97 Log.debug("Created Terminal: ", t); 98 99 try { 100 t.init(); 101 } 102 catch (Throwable e) { 103 Log.error("Terminal initialization failed; falling back to unsupported", e); 104 return new UnsupportedTerminal(); 105 } 106 107 return t; 108 } 109 110 public static synchronized void reset() { 111 term = null; 112 } 113 114 public static synchronized void resetIf(final Terminal t) { 115 if(t == term) { 116 reset(); 117 } 118 } 119 120 public static enum Type 121 { 122 AUTO, 123 WINDOWS, 124 UNIX, 125 NONE 126 } 127 128 public static synchronized void configure(final String type) { 129 checkNotNull(type); 130 System.setProperty(JLINE_TERMINAL, type); 131 } 132 133 public static synchronized void configure(final Type type) { 134 checkNotNull(type); 135 configure(type.name().toLowerCase()); 136 } 137 138 // 139 // Flavor Support 140 // 141 142 public static enum Flavor 143 { 144 WINDOWS, 145 UNIX 146 } 147 148 private static final Map<Flavor, Class<? extends Terminal>> FLAVORS = new HashMap<Flavor, Class<? extends Terminal>>(); 149 150 static { 151 // registerFlavor(Flavor.WINDOWS, AnsiWindowsTerminal.class); 152 registerFlavor(Flavor.WINDOWS, WindowsTerminal.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 }