Commit c1d0711910c35c766c55c46e6ddf89b3465a6a04

Authored by Mumfrey
1 parent 068b6528

Relocate debug sources

debug/com/mumfrey/liteloader/debug/LoginManager.java renamed to src/debug/java/com/mumfrey/liteloader/debug/LoginManager.java
1   -package com.mumfrey.liteloader.debug;
2   -
3   -import java.io.File;
4   -import java.io.FileReader;
5   -import java.io.FileWriter;
6   -import java.io.IOException;
7   -import java.lang.reflect.Type;
8   -import java.net.Proxy;
9   -import java.util.HashMap;
10   -import java.util.Map;
11   -import java.util.UUID;
12   -
13   -import javax.swing.JOptionPane;
14   -
15   -import com.google.common.base.Strings;
16   -import com.google.gson.Gson;
17   -import com.google.gson.GsonBuilder;
18   -import com.google.gson.JsonArray;
19   -import com.google.gson.JsonElement;
20   -import com.google.gson.JsonObject;
21   -import com.google.gson.JsonPrimitive;
22   -import com.google.gson.JsonSerializationContext;
23   -import com.google.gson.JsonSerializer;
24   -import com.google.gson.annotations.SerializedName;
25   -import com.mojang.authlib.Agent;
26   -import com.mojang.authlib.GameProfile;
27   -import com.mojang.authlib.UserType;
28   -import com.mojang.authlib.exceptions.AuthenticationException;
29   -import com.mojang.authlib.exceptions.InvalidCredentialsException;
30   -import com.mojang.authlib.properties.Property;
31   -import com.mojang.authlib.properties.PropertyMap;
32   -import com.mojang.authlib.yggdrasil.YggdrasilAuthenticationService;
33   -import com.mojang.authlib.yggdrasil.YggdrasilUserAuthentication;
34   -import com.mumfrey.liteloader.util.log.LiteLoaderLogger;
35   -
36   -/**
37   - * Manages login requests against Yggdrasil for use in MCP
38   - *
39   - * @author Adam Mummery-Smith
40   - */
41   -public class LoginManager
42   -{
43   - /**
44   - * Gson instance for serialising and deserialising the authentication data
45   - */
46   - private static Gson gson = new GsonBuilder().setPrettyPrinting().create();
47   -
48   - /**
49   - * Authentication service
50   - */
51   - private YggdrasilAuthenticationService authService;
52   -
53   - /**
54   - * Authentication agent
55   - */
56   - private YggdrasilUserAuthentication authentication;
57   -
58   - /**
59   - * JSON file to load/save auth data from
60   - */
61   - private File jsonFile;
62   -
63   - /**
64   - * Username read from the auth JSON file, we use this as the default in the login dialog in
65   - * case login fails. This is stored in the JSON even if authentication is not successful so that
66   - * we can display the same username next time
67   - */
68   - private String defaultUsername;
69   -
70   - /**
71   - * Minecraft screen name read from the auth JSON file. Use this as default in case the login fails
72   - * or is skipped (when offline) so that at least the Minecraft client has a sensible display name.
73   - * Defaults to user.name when not specified
74   - */
75   - private String defaultDisplayName = System.getProperty("user.name");
76   -
77   - /**
78   - * True if login should not be attempted, skips the authentication attempt and the login dialog
79   - */
80   - private boolean offline = false;
81   -
82   - /**
83   - * If authentication fails with token then the first attempt will be to use the user/pass specified
84   - * on the command line (if any). This flag is set AFTER that first attempt so that we know to display
85   - * the login dialog anyway (eg. the login on the command line was bad)
86   - */
87   - private boolean forceShowLoginDialog = false;
88   -
89   - /**
90   - * ctor
91   - *
92   - * @param jsonFile
93   - */
94   - public LoginManager(File jsonFile)
95   - {
96   - this.jsonFile = jsonFile;
97   -
98   - this.resetAuth();
99   - this.load();
100   - }
101   -
102   - /**
103   - * When authenticaion fails, we regenerate the auth service and agent because trying again with the same
104   - * client data will fail.
105   - */
106   - public void resetAuth()
107   - {
108   - this.authService = new YggdrasilAuthenticationService(Proxy.NO_PROXY, UUID.randomUUID().toString());
109   - this.authentication = new YggdrasilUserAuthentication(this.authService, Agent.MINECRAFT);
110   - }
111   -
112   - /**
113   - * Load auth data from the json file
114   - */
115   - private void load()
116   - {
117   - if (this.jsonFile != null && this.jsonFile.exists())
118   - {
119   - FileReader fileReader = null;
120   -
121   - try
122   - {
123   - fileReader = new FileReader(this.jsonFile);
124   - AuthData authData = LoginManager.gson.fromJson(fileReader, AuthData.class);
125   -
126   - if (authData != null && authData.validate())
127   - {
128   - LiteLoaderLogger.info("Initialising Yggdrasil authentication service with client token: %s", authData.getClientToken());
129   - this.authService = new YggdrasilAuthenticationService(Proxy.NO_PROXY, authData.getClientToken());
130   - this.authentication = new YggdrasilUserAuthentication(this.authService, Agent.MINECRAFT);
131   - authData.loadFromStorage(this.authentication);
132   - this.offline = authData.workOffline();
133   - this.defaultUsername = authData.getUsername();
134   - this.defaultDisplayName = authData.getDisplayName();
135   - }
136   - }
137   - catch (IOException ex) {}
138   - finally
139   - {
140   - try
141   - {
142   - if (fileReader != null) fileReader.close();
143   - }
144   - catch (IOException ex) {}
145   - }
146   - }
147   - }
148   -
149   - /**
150   - * Save auth data to the JSON file
151   - */
152   - private void save()
153   - {
154   - if (this.jsonFile != null)
155   - {
156   - FileWriter fileWriter = null;
157   -
158   - try
159   - {
160   - fileWriter = new FileWriter(this.jsonFile);
161   -
162   - AuthData authData = new AuthData(this.authService, this.authentication, this.offline, this.defaultUsername, this.defaultDisplayName);
163   - LoginManager.gson.toJson(authData, fileWriter);
164   - }
165   - catch (IOException ex) { ex.printStackTrace(); }
166   - finally
167   - {
168   - try
169   - {
170   - if (fileWriter != null) fileWriter.close();
171   - }
172   - catch (IOException ex) { ex.printStackTrace(); }
173   - }
174   - }
175   - }
176   -
177   - /**
178   - * Attempt to login. If authentication data are found on disk then tries first to log in with
179   - * the stored token. If the token login fails then attempts to log in with the username and password
180   - * specified. If no user or pass are specified or if they fail then displays a login dialog to
181   - * allow the user to login. If login succeeds then the token is stored on disk and the method
182   - * returns.
183   - *
184   - * If the user presses cancel in the login dialog then the method returns false.
185   - *
186   - * @param username User name to log in with if token login fails, if null displays the login dialog immediately
187   - * @param password Password to log in with if token login fails, if null displays the login dialog immediately
188   - * @param remainingTries Number of loops to go through before giving up, decremented for each try, specify -1 for unlimited
189   - * @return false if the user presses cancel in the login dialog, otherwise returns true
190   - */
191   - public boolean login(String username, String password, int remainingTries)
192   - {
193   - if (this.offline || remainingTries == 0)
194   - {
195   - LiteLoaderLogger.info("LoginManager is set to work offline, skipping login");
196   - return false;
197   - }
198   -
199   - LiteLoaderLogger.info("Remaining login tries: %s", remainingTries > 0 ? remainingTries : "unlimited");
200   -
201   - try
202   - {
203   - LiteLoaderLogger.info("Attempting login, contacting Mojang auth servers...");
204   -
205   - this.authentication.logIn();
206   -
207   - if (this.authentication.isLoggedIn())
208   - {
209   - LiteLoaderLogger.info("LoginManager logged in successfully. Can play online = %s", this.authentication.canPlayOnline());
210   - this.save();
211   - return true;
212   - }
213   -
214   - LiteLoaderLogger.info("LoginManager failed to log in, unspecified status.");
215   - }
216   - catch (InvalidCredentialsException ex)
217   - {
218   - LiteLoaderLogger.info("Authentication agent reported invalid credentials: %s", ex.getMessage());
219   - this.resetAuth();
220   -
221   - if (remainingTries > 1)
222   - {
223   - if (username == null)
224   - {
225   - username = this.defaultUsername;
226   - }
227   -
228   - if (this.forceShowLoginDialog || username == null || password == null)
229   - {
230   - LoginPanel loginPanel = LoginPanel.getLoginPanel(username, password, this.forceShowLoginDialog ? ex.getMessage() : null);
231   - boolean dialogResult = loginPanel.showModalDialog();
232   - this.offline = loginPanel.workOffline();
233   - this.defaultUsername = loginPanel.getUsername();
234   -
235   - if (!dialogResult)
236   - {
237   - LiteLoaderLogger.info("User cancelled login dialog");
238   - return false;
239   - }
240   -
241   - if (this.offline)
242   - {
243   - if (JOptionPane.showConfirmDialog(null, "<html>You have chosen to work offline. You will never be prompted to log in again.<br /><br />If you would like to re-enable login please delete the file <span style=\"color: #0000FF\">.auth.json</span> from the working dir<br />or press Cancel to return to the login dialog.</html>", "Confirm work offline", JOptionPane.OK_CANCEL_OPTION, JOptionPane.INFORMATION_MESSAGE) == JOptionPane.CANCEL_OPTION)
244   - {
245   - this.offline = false;
246   - remainingTries = Math.max(remainingTries, 3);
247   - }
248   - }
249   -
250   - username = loginPanel.getUsername();
251   - password = loginPanel.getPassword();
252   - this.save();
253   - }
254   -
255   - if (!Strings.isNullOrEmpty(username) && !Strings.isNullOrEmpty(password))
256   - {
257   - this.authentication.setUsername(username);
258   - this.authentication.setPassword(password);
259   - }
260   -
261   - this.forceShowLoginDialog = true;
262   - this.login(username, password, --remainingTries);
263   - }
264   - }
265   - catch (AuthenticationException ex)
266   - {
267   - ex.printStackTrace();
268   - }
269   -
270   - this.save();
271   - return false;
272   - }
273   -
274   - /**
275   - * Get whether user logged in
276   - */
277   - public boolean isLoggedIn()
278   - {
279   - return this.authentication.isLoggedIn();
280   - }
281   -
282   - /**
283   - * Get whether we are able to play online or not
284   - */
285   - public boolean canPlayOnline()
286   - {
287   - return this.authentication.canPlayOnline();
288   - }
289   -
290   - /**
291   - * Get the profile name (minecraft player name) from login
292   - */
293   - public String getProfileName()
294   - {
295   - GameProfile selectedProfile = this.authentication.getSelectedProfile();
296   - return selectedProfile != null ? selectedProfile.getName() : this.defaultDisplayName;
297   - }
298   -
299   - /**
300   - * Get the profile name (minecraft player name) from login
301   - */
302   - public String getUUID()
303   - {
304   - GameProfile selectedProfile = this.authentication.getSelectedProfile();
305   - return selectedProfile != null ? selectedProfile.getId().toString().replace("-", "") : this.defaultDisplayName;
306   - }
307   -
308   - /**
309   - * Get the session token
310   - */
311   - public String getAuthenticatedToken()
312   - {
313   - String accessToken = this.authentication.getAuthenticatedToken();
314   - return accessToken != null ? accessToken : "-";
315   - }
316   -
317   - public String getUserType()
318   - {
319   - UserType userType = this.authentication.getUserType();
320   - return (userType != null ? userType : UserType.LEGACY).toString().toLowerCase();
321   - }
322   -
323   - public String getUserProperties()
324   - {
325   - PropertyMap userProperties = this.authentication.getUserProperties();
326   - return userProperties != null ? (new GsonBuilder()).registerTypeAdapter(PropertyMap.class, new UserPropertiesSerializer()).create().toJson(userProperties) : "{}";
327   - }
328   -
329   - class UserPropertiesSerializer implements JsonSerializer<PropertyMap>
330   - {
331   - @Override
332   - public JsonElement serialize(PropertyMap propertyMap, Type argType, JsonSerializationContext context)
333   - {
334   - JsonObject result = new JsonObject();
335   -
336   - for (String key : propertyMap.keySet())
337   - {
338   - JsonArray values = new JsonArray();
339   - for (Property property : propertyMap.get(key))
340   - {
341   - values.add(new JsonPrimitive(property.getValue()));
342   - }
343   -
344   - result.add(key, values);
345   - }
346   -
347   - return result;
348   - }
349   - }
350   -
351   -
352   - /**
353   - * Struct for Gson serialisation of authenticaion settings
354   - *
355   - * @author Adam Mummery-Smith
356   - */
357   - class AuthData
358   - {
359   - @SerializedName("clientToken")
360   - private String clientToken;
361   -
362   - @SerializedName("workOffline")
363   - private boolean workOffline;
364   -
365   - @SerializedName("authData")
366   - private Map<String, Object> credentials;
367   -
368   - public AuthData()
369   - {
370   - // default ctor for Gson
371   - }
372   -
373   - public AuthData(YggdrasilAuthenticationService authService, YggdrasilUserAuthentication authentication, boolean workOffline, String defaultUserName, String defaultDisplayName)
374   - {
375   - this.clientToken = authService.getClientToken();
376   - this.credentials = authentication.saveForStorage();
377   - this.workOffline = workOffline;
378   -
379   - if (defaultUserName != null && !this.credentials.containsKey("username"))
380   - this.credentials.put("username", defaultUserName);
381   -
382   - if (defaultDisplayName != null && !this.credentials.containsKey("displayName"))
383   - this.credentials.put("displayName", defaultDisplayName);
384   - }
385   -
386   - /**
387   - * Called after Gson deserialisation to check that deserialisation was successful
388   - */
389   - public boolean validate()
390   - {
391   - if (this.clientToken == null) this.clientToken = UUID.randomUUID().toString();
392   - if (this.credentials == null) this.credentials = new HashMap<String, Object>();
393   - return true;
394   - }
395   -
396   - public String getClientToken()
397   - {
398   - return this.clientToken;
399   - }
400   -
401   - public void setClientToken(String clientToken)
402   - {
403   - this.clientToken = clientToken;
404   - }
405   -
406   - public void loadFromStorage(YggdrasilUserAuthentication authentication)
407   - {
408   - authentication.loadFromStorage(this.credentials);
409   - }
410   -
411   - public boolean workOffline()
412   - {
413   - return this.workOffline;
414   - }
415   -
416   - public String getUsername()
417   - {
418   - return this.credentials != null ? this.credentials.get("username").toString() : null;
419   - }
420   -
421   - public String getDisplayName()
422   - {
423   - return this.credentials != null && this.credentials.containsKey("displayName") ? this.credentials.get("displayName").toString() : System.getProperty("user.name");
424   - }
425   - }
426   -}
  1 +package com.mumfrey.liteloader.debug;
  2 +
  3 +import java.io.File;
  4 +import java.io.FileReader;
  5 +import java.io.FileWriter;
  6 +import java.io.IOException;
  7 +import java.lang.reflect.Type;
  8 +import java.net.Proxy;
  9 +import java.util.HashMap;
  10 +import java.util.Map;
  11 +import java.util.UUID;
  12 +
  13 +import javax.swing.JOptionPane;
  14 +
  15 +import com.google.common.base.Strings;
  16 +import com.google.gson.Gson;
  17 +import com.google.gson.GsonBuilder;
  18 +import com.google.gson.JsonArray;
  19 +import com.google.gson.JsonElement;
  20 +import com.google.gson.JsonObject;
  21 +import com.google.gson.JsonPrimitive;
  22 +import com.google.gson.JsonSerializationContext;
  23 +import com.google.gson.JsonSerializer;
  24 +import com.google.gson.annotations.SerializedName;
  25 +import com.mojang.authlib.Agent;
  26 +import com.mojang.authlib.GameProfile;
  27 +import com.mojang.authlib.UserType;
  28 +import com.mojang.authlib.exceptions.AuthenticationException;
  29 +import com.mojang.authlib.exceptions.InvalidCredentialsException;
  30 +import com.mojang.authlib.properties.Property;
  31 +import com.mojang.authlib.properties.PropertyMap;
  32 +import com.mojang.authlib.yggdrasil.YggdrasilAuthenticationService;
  33 +import com.mojang.authlib.yggdrasil.YggdrasilUserAuthentication;
  34 +import com.mumfrey.liteloader.util.log.LiteLoaderLogger;
  35 +
  36 +/**
  37 + * Manages login requests against Yggdrasil for use in MCP
  38 + *
  39 + * @author Adam Mummery-Smith
  40 + */
  41 +public class LoginManager
  42 +{
  43 + /**
  44 + * Gson instance for serialising and deserialising the authentication data
  45 + */
  46 + private static Gson gson = new GsonBuilder().setPrettyPrinting().create();
  47 +
  48 + /**
  49 + * Authentication service
  50 + */
  51 + private YggdrasilAuthenticationService authService;
  52 +
  53 + /**
  54 + * Authentication agent
  55 + */
  56 + private YggdrasilUserAuthentication authentication;
  57 +
  58 + /**
  59 + * JSON file to load/save auth data from
  60 + */
  61 + private File jsonFile;
  62 +
  63 + /**
  64 + * Username read from the auth JSON file, we use this as the default in the login dialog in
  65 + * case login fails. This is stored in the JSON even if authentication is not successful so that
  66 + * we can display the same username next time
  67 + */
  68 + private String defaultUsername;
  69 +
  70 + /**
  71 + * Minecraft screen name read from the auth JSON file. Use this as default in case the login fails
  72 + * or is skipped (when offline) so that at least the Minecraft client has a sensible display name.
  73 + * Defaults to user.name when not specified
  74 + */
  75 + private String defaultDisplayName = System.getProperty("user.name");
  76 +
  77 + /**
  78 + * True if login should not be attempted, skips the authentication attempt and the login dialog
  79 + */
  80 + private boolean offline = false;
  81 +
  82 + /**
  83 + * If authentication fails with token then the first attempt will be to use the user/pass specified
  84 + * on the command line (if any). This flag is set AFTER that first attempt so that we know to display
  85 + * the login dialog anyway (eg. the login on the command line was bad)
  86 + */
  87 + private boolean forceShowLoginDialog = false;
  88 +
  89 + /**
  90 + * ctor
  91 + *
  92 + * @param jsonFile
  93 + */
  94 + public LoginManager(File jsonFile)
  95 + {
  96 + this.jsonFile = jsonFile;
  97 +
  98 + this.resetAuth();
  99 + this.load();
  100 + }
  101 +
  102 + /**
  103 + * When authenticaion fails, we regenerate the auth service and agent because trying again with the same
  104 + * client data will fail.
  105 + */
  106 + public void resetAuth()
  107 + {
  108 + this.authService = new YggdrasilAuthenticationService(Proxy.NO_PROXY, UUID.randomUUID().toString());
  109 + this.authentication = new YggdrasilUserAuthentication(this.authService, Agent.MINECRAFT);
  110 + }
  111 +
  112 + /**
  113 + * Load auth data from the json file
  114 + */
  115 + private void load()
  116 + {
  117 + if (this.jsonFile != null && this.jsonFile.exists())
  118 + {
  119 + FileReader fileReader = null;
  120 +
  121 + try
  122 + {
  123 + fileReader = new FileReader(this.jsonFile);
  124 + AuthData authData = LoginManager.gson.fromJson(fileReader, AuthData.class);
  125 +
  126 + if (authData != null && authData.validate())
  127 + {
  128 + LiteLoaderLogger.info("Initialising Yggdrasil authentication service with client token: %s", authData.getClientToken());
  129 + this.authService = new YggdrasilAuthenticationService(Proxy.NO_PROXY, authData.getClientToken());
  130 + this.authentication = new YggdrasilUserAuthentication(this.authService, Agent.MINECRAFT);
  131 + authData.loadFromStorage(this.authentication);
  132 + this.offline = authData.workOffline();
  133 + this.defaultUsername = authData.getUsername();
  134 + this.defaultDisplayName = authData.getDisplayName();
  135 + }
  136 + }
  137 + catch (IOException ex) {}
  138 + finally
  139 + {
  140 + try
  141 + {
  142 + if (fileReader != null) fileReader.close();
  143 + }
  144 + catch (IOException ex) {}
  145 + }
  146 + }
  147 + }
  148 +
  149 + /**
  150 + * Save auth data to the JSON file
  151 + */
  152 + private void save()
  153 + {
  154 + if (this.jsonFile != null)
  155 + {
  156 + FileWriter fileWriter = null;
  157 +
  158 + try
  159 + {
  160 + fileWriter = new FileWriter(this.jsonFile);
  161 +
  162 + AuthData authData = new AuthData(this.authService, this.authentication, this.offline, this.defaultUsername, this.defaultDisplayName);
  163 + LoginManager.gson.toJson(authData, fileWriter);
  164 + }
  165 + catch (IOException ex) { ex.printStackTrace(); }
  166 + finally
  167 + {
  168 + try
  169 + {
  170 + if (fileWriter != null) fileWriter.close();
  171 + }
  172 + catch (IOException ex) { ex.printStackTrace(); }
  173 + }
  174 + }
  175 + }
  176 +
  177 + /**
  178 + * Attempt to login. If authentication data are found on disk then tries first to log in with
  179 + * the stored token. If the token login fails then attempts to log in with the username and password
  180 + * specified. If no user or pass are specified or if they fail then displays a login dialog to
  181 + * allow the user to login. If login succeeds then the token is stored on disk and the method
  182 + * returns.
  183 + *
  184 + * If the user presses cancel in the login dialog then the method returns false.
  185 + *
  186 + * @param username User name to log in with if token login fails, if null displays the login dialog immediately
  187 + * @param password Password to log in with if token login fails, if null displays the login dialog immediately
  188 + * @param remainingTries Number of loops to go through before giving up, decremented for each try, specify -1 for unlimited
  189 + * @return false if the user presses cancel in the login dialog, otherwise returns true
  190 + */
  191 + public boolean login(String username, String password, int remainingTries)
  192 + {
  193 + if (this.offline || remainingTries == 0)
  194 + {
  195 + LiteLoaderLogger.info("LoginManager is set to work offline, skipping login");
  196 + return false;
  197 + }
  198 +
  199 + LiteLoaderLogger.info("Remaining login tries: %s", remainingTries > 0 ? remainingTries : "unlimited");
  200 +
  201 + try
  202 + {
  203 + LiteLoaderLogger.info("Attempting login, contacting Mojang auth servers...");
  204 +
  205 + this.authentication.logIn();
  206 +
  207 + if (this.authentication.isLoggedIn())
  208 + {
  209 + LiteLoaderLogger.info("LoginManager logged in successfully. Can play online = %s", this.authentication.canPlayOnline());
  210 + this.save();
  211 + return true;
  212 + }
  213 +
  214 + LiteLoaderLogger.info("LoginManager failed to log in, unspecified status.");
  215 + }
  216 + catch (InvalidCredentialsException ex)
  217 + {
  218 + LiteLoaderLogger.info("Authentication agent reported invalid credentials: %s", ex.getMessage());
  219 + this.resetAuth();
  220 +
  221 + if (remainingTries > 1)
  222 + {
  223 + if (username == null)
  224 + {
  225 + username = this.defaultUsername;
  226 + }
  227 +
  228 + if (this.forceShowLoginDialog || username == null || password == null)
  229 + {
  230 + LoginPanel loginPanel = LoginPanel.getLoginPanel(username, password, this.forceShowLoginDialog ? ex.getMessage() : null);
  231 + boolean dialogResult = loginPanel.showModalDialog();
  232 + this.offline = loginPanel.workOffline();
  233 + this.defaultUsername = loginPanel.getUsername();
  234 +
  235 + if (!dialogResult)
  236 + {
  237 + LiteLoaderLogger.info("User cancelled login dialog");
  238 + return false;
  239 + }
  240 +
  241 + if (this.offline)
  242 + {
  243 + if (JOptionPane.showConfirmDialog(null, "<html>You have chosen to work offline. You will never be prompted to log in again.<br /><br />If you would like to re-enable login please delete the file <span style=\"color: #0000FF\">.auth.json</span> from the working dir<br />or press Cancel to return to the login dialog.</html>", "Confirm work offline", JOptionPane.OK_CANCEL_OPTION, JOptionPane.INFORMATION_MESSAGE) == JOptionPane.CANCEL_OPTION)
  244 + {
  245 + this.offline = false;
  246 + remainingTries = Math.max(remainingTries, 3);
  247 + }
  248 + }
  249 +
  250 + username = loginPanel.getUsername();
  251 + password = loginPanel.getPassword();
  252 + this.save();
  253 + }
  254 +
  255 + if (!Strings.isNullOrEmpty(username) && !Strings.isNullOrEmpty(password))
  256 + {
  257 + this.authentication.setUsername(username);
  258 + this.authentication.setPassword(password);
  259 + }
  260 +
  261 + this.forceShowLoginDialog = true;
  262 + this.login(username, password, --remainingTries);
  263 + }
  264 + }
  265 + catch (AuthenticationException ex)
  266 + {
  267 + ex.printStackTrace();
  268 + }
  269 +
  270 + this.save();
  271 + return false;
  272 + }
  273 +
  274 + /**
  275 + * Get whether user logged in
  276 + */
  277 + public boolean isLoggedIn()
  278 + {
  279 + return this.authentication.isLoggedIn();
  280 + }
  281 +
  282 + /**
  283 + * Get whether we are able to play online or not
  284 + */
  285 + public boolean canPlayOnline()
  286 + {
  287 + return this.authentication.canPlayOnline();
  288 + }
  289 +
  290 + /**
  291 + * Get the profile name (minecraft player name) from login
  292 + */
  293 + public String getProfileName()
  294 + {
  295 + GameProfile selectedProfile = this.authentication.getSelectedProfile();
  296 + return selectedProfile != null ? selectedProfile.getName() : this.defaultDisplayName;
  297 + }
  298 +
  299 + /**
  300 + * Get the profile name (minecraft player name) from login
  301 + */
  302 + public String getUUID()
  303 + {
  304 + GameProfile selectedProfile = this.authentication.getSelectedProfile();
  305 + return selectedProfile != null ? selectedProfile.getId().toString().replace("-", "") : this.defaultDisplayName;
  306 + }
  307 +
  308 + /**
  309 + * Get the session token
  310 + */
  311 + public String getAuthenticatedToken()
  312 + {
  313 + String accessToken = this.authentication.getAuthenticatedToken();
  314 + return accessToken != null ? accessToken : "-";
  315 + }
  316 +
  317 + public String getUserType()
  318 + {
  319 + UserType userType = this.authentication.getUserType();
  320 + return (userType != null ? userType : UserType.LEGACY).toString().toLowerCase();
  321 + }
  322 +
  323 + public String getUserProperties()
  324 + {
  325 + PropertyMap userProperties = this.authentication.getUserProperties();
  326 + return userProperties != null ? (new GsonBuilder()).registerTypeAdapter(PropertyMap.class, new UserPropertiesSerializer()).create().toJson(userProperties) : "{}";
  327 + }
  328 +
  329 + class UserPropertiesSerializer implements JsonSerializer<PropertyMap>
  330 + {
  331 + @Override
  332 + public JsonElement serialize(PropertyMap propertyMap, Type argType, JsonSerializationContext context)
  333 + {
  334 + JsonObject result = new JsonObject();
  335 +
  336 + for (String key : propertyMap.keySet())
  337 + {
  338 + JsonArray values = new JsonArray();
  339 + for (Property property : propertyMap.get(key))
  340 + {
  341 + values.add(new JsonPrimitive(property.getValue()));
  342 + }
  343 +
  344 + result.add(key, values);
  345 + }
  346 +
  347 + return result;
  348 + }
  349 + }
  350 +
  351 +
  352 + /**
  353 + * Struct for Gson serialisation of authenticaion settings
  354 + *
  355 + * @author Adam Mummery-Smith
  356 + */
  357 + class AuthData
  358 + {
  359 + @SerializedName("clientToken")
  360 + private String clientToken;
  361 +
  362 + @SerializedName("workOffline")
  363 + private boolean workOffline;
  364 +
  365 + @SerializedName("authData")
  366 + private Map<String, Object> credentials;
  367 +
  368 + public AuthData()
  369 + {
  370 + // default ctor for Gson
  371 + }
  372 +
  373 + public AuthData(YggdrasilAuthenticationService authService, YggdrasilUserAuthentication authentication, boolean workOffline, String defaultUserName, String defaultDisplayName)
  374 + {
  375 + this.clientToken = authService.getClientToken();
  376 + this.credentials = authentication.saveForStorage();
  377 + this.workOffline = workOffline;
  378 +
  379 + if (defaultUserName != null && !this.credentials.containsKey("username"))
  380 + this.credentials.put("username", defaultUserName);
  381 +
  382 + if (defaultDisplayName != null && !this.credentials.containsKey("displayName"))
  383 + this.credentials.put("displayName", defaultDisplayName);
  384 + }
  385 +
  386 + /**
  387 + * Called after Gson deserialisation to check that deserialisation was successful
  388 + */
  389 + public boolean validate()
  390 + {
  391 + if (this.clientToken == null) this.clientToken = UUID.randomUUID().toString();
  392 + if (this.credentials == null) this.credentials = new HashMap<String, Object>();
  393 + return true;
  394 + }
  395 +
  396 + public String getClientToken()
  397 + {
  398 + return this.clientToken;
  399 + }
  400 +
  401 + public void setClientToken(String clientToken)
  402 + {
  403 + this.clientToken = clientToken;
  404 + }
  405 +
  406 + public void loadFromStorage(YggdrasilUserAuthentication authentication)
  407 + {
  408 + authentication.loadFromStorage(this.credentials);
  409 + }
  410 +
  411 + public boolean workOffline()
  412 + {
  413 + return this.workOffline;
  414 + }
  415 +
  416 + public String getUsername()
  417 + {
  418 + return this.credentials != null ? this.credentials.get("username").toString() : null;
  419 + }
  420 +
  421 + public String getDisplayName()
  422 + {
  423 + return this.credentials != null && this.credentials.containsKey("displayName") ? this.credentials.get("displayName").toString() : System.getProperty("user.name");
  424 + }
  425 + }
  426 +}
... ...
debug/com/mumfrey/liteloader/debug/LoginPanel.java renamed to src/debug/java/com/mumfrey/liteloader/debug/LoginPanel.java
1   -package com.mumfrey.liteloader.debug;
2   -
3   -import static javax.swing.WindowConstants.*;
4   -
5   -import java.awt.*;
6   -import java.awt.event.ActionEvent;
7   -import java.awt.event.ActionListener;
8   -import java.awt.event.WindowAdapter;
9   -import java.awt.event.WindowEvent;
10   -import java.util.ArrayList;
11   -import java.util.List;
12   -
13   -import javax.swing.JButton;
14   -import javax.swing.JCheckBox;
15   -import javax.swing.JDialog;
16   -import javax.swing.JLabel;
17   -import javax.swing.JPanel;
18   -import javax.swing.UIManager;
19   -import javax.swing.border.EmptyBorder;
20   -import javax.swing.border.TitledBorder;
21   -
22   -/**
23   - * JPanel displayed in a JDialog to prompt the user for login credentials for minecraft
24   - *
25   - * @author Adam Mummery-Smith
26   - */
27   -public class LoginPanel extends JPanel
28   -{
29   - private static final long serialVersionUID = 1L;
30   -
31   - private GridBagLayout panelLoginLayout;
32   -
33   - private JPanel panelTitle;
34   - private JPanel panelCentre;
35   - private JPanel panelPadding;
36   - private JPanel panelBottom;
37   - private JLabel lblTitle;
38   - private JLabel lblSubTitle;
39   - private JLabel lblMessage;
40   - private JLabel lblUserName;
41   - private JLabel lblPassword;
42   - private TextField txtUsername;
43   - private TextField txtPassword;
44   - private JButton btnLogin;
45   - private JButton btnCancel;
46   - private JCheckBox chkOffline;
47   -
48   - private JDialog dialog;
49   -
50   - private ListFocusTraversal tabOrder = new ListFocusTraversal();
51   -
52   - private boolean dialogResult = false;
53   -
54   - public LoginPanel(String username, String password, String error)
55   - {
56   - Color backColour = new Color(102, 118, 144);
57   -
58   - this.setFocusable(false);
59   - this.setPreferredSize(new Dimension(400, 260));
60   - this.setBackground(new Color(105, 105, 105));
61   - this.setLayout(new BorderLayout(0, 0));
62   -
63   - this.panelTitle = new JPanel();
64   - this.panelTitle.setBackground(backColour);
65   - this.panelTitle.setPreferredSize(new Dimension(400, 64));
66   - this.panelTitle.setLayout(new FlowLayout(FlowLayout.CENTER, 5, 5));
67   -
68   - this.panelBottom = new JPanel();
69   - this.panelBottom.setBackground(backColour);
70   - this.panelBottom.setPreferredSize(new Dimension(400, 32));
71   - this.panelBottom.setLayout(new FlowLayout(FlowLayout.CENTER, 5, 5));
72   -
73   - this.panelPadding = new JPanel();
74   - this.panelPadding.setBorder(new EmptyBorder(4, 8, 8, 8));
75   - this.panelPadding.setOpaque(false);
76   - this.panelPadding.setLayout(new BorderLayout(0, 0));
77   -
78   - this.panelCentre = new JPanel();
79   - this.panelCentre.setOpaque(false);
80   - this.panelCentre.setBorder(new TitledBorder(UIManager.getBorder("TitledBorder.border"), "Yggdrasil Login", TitledBorder.LEADING, TitledBorder.TOP, null, Color.WHITE));
81   - this.panelLoginLayout = new GridBagLayout();
82   - this.panelLoginLayout.columnWidths = new int[] {30, 80, 120, 120, 30};
83   - this.panelLoginLayout.rowHeights = new int[] {24, 32, 32, 32};
84   - this.panelLoginLayout.columnWeights = new double[]{0.0, 0.0, 0.0, 0.0, Double.MIN_VALUE};
85   - this.panelLoginLayout.rowWeights = new double[]{0.0, 0.0, 0.0, 0.0};
86   - this.panelCentre.setLayout(this.panelLoginLayout);
87   -
88   - this.lblTitle = new JLabel("Log in to minecraft.net");
89   - this.lblTitle.setBorder(new EmptyBorder(4, 16, 0, 16));
90   - this.lblTitle.setFont(new Font("Tahoma", Font.BOLD, 18));
91   - this.lblTitle.setForeground(Color.WHITE);
92   - this.lblTitle.setPreferredSize(new Dimension(400, 26));
93   -
94   - this.lblSubTitle = new JLabel("Your password will not be stored, logging in with Yggdrasil");
95   - this.lblSubTitle.setBorder(new EmptyBorder(0, 16, 0, 16));
96   - this.lblSubTitle.setForeground(Color.WHITE);
97   - this.lblSubTitle.setPreferredSize(new Dimension(400, 16));
98   -
99   - this.lblMessage = new JLabel("Enter your login details for minecraft.net");
100   - this.lblMessage.setForeground(Color.WHITE);
101   -
102   - this.lblUserName = new JLabel("User name");
103   - this.lblUserName.setForeground(Color.WHITE);
104   -
105   - this.lblPassword = new JLabel("Password");
106   - this.lblPassword.setForeground(Color.WHITE);
107   -
108   - this.txtUsername = new TextField();
109   - this.txtUsername.setPreferredSize(new Dimension(200, 22));
110   - this.txtUsername.setText(username);
111   -
112   - this.txtPassword = new TextField();
113   - this.txtPassword.setEchoChar('*');
114   - this.txtPassword.setPreferredSize(new Dimension(200, 22));
115   - this.txtPassword.setText(password);
116   -
117   - this.btnLogin = new JButton("Log in");
118   - this.btnLogin.addActionListener(new ActionListener() {
119   - @Override public void actionPerformed(ActionEvent e) {
120   - LoginPanel.this.onLoginClick();
121   - }
122   - });
123   -
124   - this.btnCancel = new JButton("Cancel");
125   - this.btnCancel.addActionListener(new ActionListener() {
126   - @Override public void actionPerformed(ActionEvent e) {
127   - LoginPanel.this.onCancelClick();
128   - }
129   - });
130   -
131   - this.chkOffline = new JCheckBox("Never ask me to log in (always run offline)");
132   - this.chkOffline.setPreferredSize(new Dimension(380, 23));
133   - this.chkOffline.setForeground(Color.WHITE);
134   - this.chkOffline.setOpaque(false);
135   - this.chkOffline.addActionListener(new ActionListener()
136   - {
137   - @Override public void actionPerformed(ActionEvent e)
138   - {
139   - LoginPanel.this.onOfflineCheckedChanged();
140   - }
141   - });
142   -
143   - GridBagConstraints lblMessageConstraints = new GridBagConstraints();
144   - lblMessageConstraints.anchor = GridBagConstraints.WEST;
145   - lblMessageConstraints.gridwidth = 2;
146   - lblMessageConstraints.insets = new Insets(0, 0, 5, 5);
147   - lblMessageConstraints.gridx = 2;
148   - lblMessageConstraints.gridy = 0;
149   -
150   - GridBagConstraints lblUserNameConstraints = new GridBagConstraints();
151   - lblUserNameConstraints.anchor = GridBagConstraints.WEST;
152   - lblUserNameConstraints.fill = GridBagConstraints.VERTICAL;
153   - lblUserNameConstraints.insets = new Insets(0, 0, 5, 5);
154   - lblUserNameConstraints.gridx = 1;
155   - lblUserNameConstraints.gridy = 1;
156   -
157   - GridBagConstraints lblPasswordConstraints = new GridBagConstraints();
158   - lblPasswordConstraints.anchor = GridBagConstraints.WEST;
159   - lblPasswordConstraints.fill = GridBagConstraints.VERTICAL;
160   - lblPasswordConstraints.insets = new Insets(0, 0, 5, 5);
161   - lblPasswordConstraints.gridx = 1;
162   - lblPasswordConstraints.gridy = 2;
163   -
164   - GridBagConstraints txtUsernameConstraints = new GridBagConstraints();
165   - txtUsernameConstraints.gridwidth = 2;
166   - txtUsernameConstraints.fill = GridBagConstraints.HORIZONTAL;
167   - txtUsernameConstraints.insets = new Insets(0, 0, 5, 0);
168   - txtUsernameConstraints.gridx = 2;
169   - txtUsernameConstraints.gridy = 1;
170   -
171   - GridBagConstraints txtPasswordConstraints = new GridBagConstraints();
172   - txtPasswordConstraints.gridwidth = 2;
173   - txtPasswordConstraints.insets = new Insets(0, 0, 5, 0);
174   - txtPasswordConstraints.fill = GridBagConstraints.HORIZONTAL;
175   - txtPasswordConstraints.gridx = 2;
176   - txtPasswordConstraints.gridy = 2;
177   -
178   - GridBagConstraints btnLoginConstraints = new GridBagConstraints();
179   - btnLoginConstraints.fill = GridBagConstraints.HORIZONTAL;
180   - btnLoginConstraints.gridx = 3;
181   - btnLoginConstraints.gridy = 3;
182   -
183   - GridBagConstraints btnCancelConstraints = new GridBagConstraints();
184   - btnCancelConstraints.anchor = GridBagConstraints.EAST;
185   - btnCancelConstraints.insets = new Insets(0, 0, 0, 5);
186   - btnCancelConstraints.gridx = 2;
187   - btnCancelConstraints.gridy = 3;
188   -
189   - this.add(this.panelTitle, BorderLayout.NORTH);
190   - this.add(this.panelPadding, BorderLayout.CENTER);
191   - this.add(this.panelBottom, BorderLayout.SOUTH);
192   -
193   - this.panelPadding.add(this.panelCentre);
194   -
195   - this.panelTitle.add(this.lblTitle);
196   - this.panelTitle.add(this.lblSubTitle);
197   -
198   - this.panelCentre.add(this.lblMessage, lblMessageConstraints);
199   - this.panelCentre.add(this.lblUserName, lblUserNameConstraints);
200   - this.panelCentre.add(this.lblPassword, lblPasswordConstraints);
201   - this.panelCentre.add(this.txtUsername, txtUsernameConstraints);
202   - this.panelCentre.add(this.txtPassword, txtPasswordConstraints);
203   - this.panelCentre.add(this.btnLogin, btnLoginConstraints);
204   - this.panelCentre.add(this.btnCancel, btnCancelConstraints);
205   -
206   - this.panelBottom.add(this.chkOffline);
207   -
208   - this.tabOrder.add(this.txtUsername);
209   - this.tabOrder.add(this.txtPassword);
210   - this.tabOrder.add(this.btnLogin);
211   - this.tabOrder.add(this.btnCancel);
212   - this.tabOrder.add(this.chkOffline);
213   -
214   - if (error != null)
215   - {
216   - this.lblMessage.setText(error);
217   - this.lblMessage.setForeground(new Color(255, 180, 180));
218   - }
219   - }
220   -
221   - protected void onShowDialog()
222   - {
223   - if (this.txtUsername.getText().length() > 0)
224   - {
225   - if (this.txtPassword.getText().length() > 0)
226   - this.txtUsername.select(0, this.txtUsername.getText().length());
227   - else
228   - this.txtPassword.requestFocusInWindow();
229   - }
230   - }
231   -
232   - protected void onLoginClick()
233   - {
234   - this.dialogResult = true;
235   - this.dialog.setVisible(false);
236   - }
237   -
238   - protected void onCancelClick()
239   - {
240   - this.dialog.setVisible(false);
241   - }
242   -
243   - protected void onOfflineCheckedChanged()
244   - {
245   - boolean selected = this.chkOffline.isSelected();
246   - this.btnLogin.setText(selected ? "Work Offline" : "Log In");
247   - this.txtUsername.setEnabled(!selected);
248   - this.txtPassword.setEnabled(!selected);
249   - }
250   -
251   - /**
252   - * @param dialog
253   - */
254   - public void setDialog(JDialog dialog)
255   - {
256   - this.dialog = dialog;
257   -
258   - this.dialog.addWindowListener(new WindowAdapter()
259   - {
260   - @Override
261   - public void windowOpened(WindowEvent e)
262   - {
263   - LoginPanel.this.onShowDialog();
264   - }
265   - });
266   -
267   - this.dialog.getRootPane().setDefaultButton(this.btnLogin);
268   - this.dialog.setFocusTraversalPolicy(this.tabOrder);
269   - }
270   -
271   - public boolean showModalDialog()
272   - {
273   - this.dialog.setVisible(true);
274   - this.dialog.dispose();
275   - return this.dialogResult;
276   - }
277   -
278   - public String getUsername()
279   - {
280   - return this.txtUsername.getText();
281   - }
282   -
283   - public String getPassword()
284   - {
285   - return this.txtPassword.getText();
286   - }
287   -
288   - public boolean workOffline()
289   - {
290   - return this.chkOffline.isSelected();
291   - }
292   -
293   - public static LoginPanel getLoginPanel(String username, String password, String error)
294   - {
295   - if (username == null) username = "";
296   - if (password == null) password = "";
297   -
298   - final JDialog dialog = new JDialog();
299   - final LoginPanel panel = new LoginPanel(username, password, error);
300   - panel.setDialog(dialog);
301   -
302   - dialog.setContentPane(panel);
303   - dialog.setTitle("Yggdrasil Login");
304   - dialog.setResizable(false);
305   - dialog.pack();
306   - dialog.setDefaultCloseOperation(DISPOSE_ON_CLOSE);
307   - dialog.setLocationRelativeTo(null);
308   - dialog.setModal(true);
309   -
310   - return panel;
311   - }
312   -
313   - class ListFocusTraversal extends FocusTraversalPolicy
314   - {
315   - private final List<Component> components = new ArrayList<Component>();
316   -
317   - void add(Component component)
318   - {
319   - this.components.add(component);
320   - }
321   -
322   - @Override
323   - public Component getComponentAfter(Container container, Component component)
324   - {
325   - int index = this.components.indexOf(component) + 1;
326   - if (index >= this.components.size()) return this.components.get(0);
327   - return this.components.get(index);
328   - }
329   -
330   - @Override
331   - public Component getComponentBefore(Container container, Component component)
332   - {
333   - int index = this.components.indexOf(component) - 1;
334   - if (index < 0) return this.getLastComponent(container);
335   - return this.components.get(index);
336   - }
337   -
338   - @Override
339   - public Component getFirstComponent(Container container)
340   - {
341   - return this.components.get(0);
342   - }
343   -
344   - @Override
345   - public Component getLastComponent(Container container)
346   - {
347   - return this.components.get(this.components.size() - 1);
348   - }
349   -
350   - @Override
351   - public Component getDefaultComponent(Container container)
352   - {
353   - return this.getFirstComponent(container);
354   - }
355   - }
356   -}
  1 +package com.mumfrey.liteloader.debug;
  2 +
  3 +import static javax.swing.WindowConstants.*;
  4 +
  5 +import java.awt.*;
  6 +import java.awt.event.ActionEvent;
  7 +import java.awt.event.ActionListener;
  8 +import java.awt.event.WindowAdapter;
  9 +import java.awt.event.WindowEvent;
  10 +import java.util.ArrayList;
  11 +import java.util.List;
  12 +
  13 +import javax.swing.JButton;
  14 +import javax.swing.JCheckBox;
  15 +import javax.swing.JDialog;
  16 +import javax.swing.JLabel;
  17 +import javax.swing.JPanel;
  18 +import javax.swing.UIManager;
  19 +import javax.swing.border.EmptyBorder;
  20 +import javax.swing.border.TitledBorder;
  21 +
  22 +/**
  23 + * JPanel displayed in a JDialog to prompt the user for login credentials for minecraft
  24 + *
  25 + * @author Adam Mummery-Smith
  26 + */
  27 +public class LoginPanel extends JPanel
  28 +{
  29 + private static final long serialVersionUID = 1L;
  30 +
  31 + private GridBagLayout panelLoginLayout;
  32 +
  33 + private JPanel panelTitle;
  34 + private JPanel panelCentre;
  35 + private JPanel panelPadding;
  36 + private JPanel panelBottom;
  37 + private JLabel lblTitle;
  38 + private JLabel lblSubTitle;
  39 + private JLabel lblMessage;
  40 + private JLabel lblUserName;
  41 + private JLabel lblPassword;
  42 + private TextField txtUsername;
  43 + private TextField txtPassword;
  44 + private JButton btnLogin;
  45 + private JButton btnCancel;
  46 + private JCheckBox chkOffline;
  47 +
  48 + private JDialog dialog;
  49 +
  50 + private ListFocusTraversal tabOrder = new ListFocusTraversal();
  51 +
  52 + private boolean dialogResult = false;
  53 +
  54 + public LoginPanel(String username, String password, String error)
  55 + {
  56 + Color backColour = new Color(102, 118, 144);
  57 +
  58 + this.setFocusable(false);
  59 + this.setPreferredSize(new Dimension(400, 260));
  60 + this.setBackground(new Color(105, 105, 105));
  61 + this.setLayout(new BorderLayout(0, 0));
  62 +
  63 + this.panelTitle = new JPanel();
  64 + this.panelTitle.setBackground(backColour);
  65 + this.panelTitle.setPreferredSize(new Dimension(400, 64));
  66 + this.panelTitle.setLayout(new FlowLayout(FlowLayout.CENTER, 5, 5));
  67 +
  68 + this.panelBottom = new JPanel();
  69 + this.panelBottom.setBackground(backColour);
  70 + this.panelBottom.setPreferredSize(new Dimension(400, 32));
  71 + this.panelBottom.setLayout(new FlowLayout(FlowLayout.CENTER, 5, 5));
  72 +
  73 + this.panelPadding = new JPanel();
  74 + this.panelPadding.setBorder(new EmptyBorder(4, 8, 8, 8));
  75 + this.panelPadding.setOpaque(false);
  76 + this.panelPadding.setLayout(new BorderLayout(0, 0));
  77 +
  78 + this.panelCentre = new JPanel();
  79 + this.panelCentre.setOpaque(false);
  80 + this.panelCentre.setBorder(new TitledBorder(UIManager.getBorder("TitledBorder.border"), "Yggdrasil Login", TitledBorder.LEADING, TitledBorder.TOP, null, Color.WHITE));
  81 + this.panelLoginLayout = new GridBagLayout();
  82 + this.panelLoginLayout.columnWidths = new int[] {30, 80, 120, 120, 30};
  83 + this.panelLoginLayout.rowHeights = new int[] {24, 32, 32, 32};
  84 + this.panelLoginLayout.columnWeights = new double[]{0.0, 0.0, 0.0, 0.0, Double.MIN_VALUE};
  85 + this.panelLoginLayout.rowWeights = new double[]{0.0, 0.0, 0.0, 0.0};
  86 + this.panelCentre.setLayout(this.panelLoginLayout);
  87 +
  88 + this.lblTitle = new JLabel("Log in to minecraft.net");
  89 + this.lblTitle.setBorder(new EmptyBorder(4, 16, 0, 16));
  90 + this.lblTitle.setFont(new Font("Tahoma", Font.BOLD, 18));
  91 + this.lblTitle.setForeground(Color.WHITE);
  92 + this.lblTitle.setPreferredSize(new Dimension(400, 26));
  93 +
  94 + this.lblSubTitle = new JLabel("Your password will not be stored, logging in with Yggdrasil");
  95 + this.lblSubTitle.setBorder(new EmptyBorder(0, 16, 0, 16));
  96 + this.lblSubTitle.setForeground(Color.WHITE);
  97 + this.lblSubTitle.setPreferredSize(new Dimension(400, 16));
  98 +
  99 + this.lblMessage = new JLabel("Enter your login details for minecraft.net");
  100 + this.lblMessage.setForeground(Color.WHITE);
  101 +
  102 + this.lblUserName = new JLabel("User name");
  103 + this.lblUserName.setForeground(Color.WHITE);
  104 +
  105 + this.lblPassword = new JLabel("Password");
  106 + this.lblPassword.setForeground(Color.WHITE);
  107 +
  108 + this.txtUsername = new TextField();
  109 + this.txtUsername.setPreferredSize(new Dimension(200, 22));
  110 + this.txtUsername.setText(username);
  111 +
  112 + this.txtPassword = new TextField();
  113 + this.txtPassword.setEchoChar('*');
  114 + this.txtPassword.setPreferredSize(new Dimension(200, 22));
  115 + this.txtPassword.setText(password);
  116 +
  117 + this.btnLogin = new JButton("Log in");
  118 + this.btnLogin.addActionListener(new ActionListener() {
  119 + @Override public void actionPerformed(ActionEvent e) {
  120 + LoginPanel.this.onLoginClick();
  121 + }
  122 + });
  123 +
  124 + this.btnCancel = new JButton("Cancel");
  125 + this.btnCancel.addActionListener(new ActionListener() {
  126 + @Override public void actionPerformed(ActionEvent e) {
  127 + LoginPanel.this.onCancelClick();
  128 + }
  129 + });
  130 +
  131 + this.chkOffline = new JCheckBox("Never ask me to log in (always run offline)");
  132 + this.chkOffline.setPreferredSize(new Dimension(380, 23));
  133 + this.chkOffline.setForeground(Color.WHITE);
  134 + this.chkOffline.setOpaque(false);
  135 + this.chkOffline.addActionListener(new ActionListener()
  136 + {
  137 + @Override public void actionPerformed(ActionEvent e)
  138 + {
  139 + LoginPanel.this.onOfflineCheckedChanged();
  140 + }
  141 + });
  142 +
  143 + GridBagConstraints lblMessageConstraints = new GridBagConstraints();
  144 + lblMessageConstraints.anchor = GridBagConstraints.WEST;
  145 + lblMessageConstraints.gridwidth = 2;
  146 + lblMessageConstraints.insets = new Insets(0, 0, 5, 5);
  147 + lblMessageConstraints.gridx = 2;
  148 + lblMessageConstraints.gridy = 0;
  149 +
  150 + GridBagConstraints lblUserNameConstraints = new GridBagConstraints();
  151 + lblUserNameConstraints.anchor = GridBagConstraints.WEST;
  152 + lblUserNameConstraints.fill = GridBagConstraints.VERTICAL;
  153 + lblUserNameConstraints.insets = new Insets(0, 0, 5, 5);
  154 + lblUserNameConstraints.gridx = 1;
  155 + lblUserNameConstraints.gridy = 1;
  156 +
  157 + GridBagConstraints lblPasswordConstraints = new GridBagConstraints();
  158 + lblPasswordConstraints.anchor = GridBagConstraints.WEST;
  159 + lblPasswordConstraints.fill = GridBagConstraints.VERTICAL;
  160 + lblPasswordConstraints.insets = new Insets(0, 0, 5, 5);
  161 + lblPasswordConstraints.gridx = 1;
  162 + lblPasswordConstraints.gridy = 2;
  163 +
  164 + GridBagConstraints txtUsernameConstraints = new GridBagConstraints();
  165 + txtUsernameConstraints.gridwidth = 2;
  166 + txtUsernameConstraints.fill = GridBagConstraints.HORIZONTAL;
  167 + txtUsernameConstraints.insets = new Insets(0, 0, 5, 0);
  168 + txtUsernameConstraints.gridx = 2;
  169 + txtUsernameConstraints.gridy = 1;
  170 +
  171 + GridBagConstraints txtPasswordConstraints = new GridBagConstraints();
  172 + txtPasswordConstraints.gridwidth = 2;
  173 + txtPasswordConstraints.insets = new Insets(0, 0, 5, 0);
  174 + txtPasswordConstraints.fill = GridBagConstraints.HORIZONTAL;
  175 + txtPasswordConstraints.gridx = 2;
  176 + txtPasswordConstraints.gridy = 2;
  177 +
  178 + GridBagConstraints btnLoginConstraints = new GridBagConstraints();
  179 + btnLoginConstraints.fill = GridBagConstraints.HORIZONTAL;
  180 + btnLoginConstraints.gridx = 3;
  181 + btnLoginConstraints.gridy = 3;
  182 +
  183 + GridBagConstraints btnCancelConstraints = new GridBagConstraints();
  184 + btnCancelConstraints.anchor = GridBagConstraints.EAST;
  185 + btnCancelConstraints.insets = new Insets(0, 0, 0, 5);
  186 + btnCancelConstraints.gridx = 2;
  187 + btnCancelConstraints.gridy = 3;
  188 +
  189 + this.add(this.panelTitle, BorderLayout.NORTH);
  190 + this.add(this.panelPadding, BorderLayout.CENTER);
  191 + this.add(this.panelBottom, BorderLayout.SOUTH);
  192 +
  193 + this.panelPadding.add(this.panelCentre);
  194 +
  195 + this.panelTitle.add(this.lblTitle);
  196 + this.panelTitle.add(this.lblSubTitle);
  197 +
  198 + this.panelCentre.add(this.lblMessage, lblMessageConstraints);
  199 + this.panelCentre.add(this.lblUserName, lblUserNameConstraints);
  200 + this.panelCentre.add(this.lblPassword, lblPasswordConstraints);
  201 + this.panelCentre.add(this.txtUsername, txtUsernameConstraints);
  202 + this.panelCentre.add(this.txtPassword, txtPasswordConstraints);
  203 + this.panelCentre.add(this.btnLogin, btnLoginConstraints);
  204 + this.panelCentre.add(this.btnCancel, btnCancelConstraints);
  205 +
  206 + this.panelBottom.add(this.chkOffline);
  207 +
  208 + this.tabOrder.add(this.txtUsername);
  209 + this.tabOrder.add(this.txtPassword);
  210 + this.tabOrder.add(this.btnLogin);
  211 + this.tabOrder.add(this.btnCancel);
  212 + this.tabOrder.add(this.chkOffline);
  213 +
  214 + if (error != null)
  215 + {
  216 + this.lblMessage.setText(error);
  217 + this.lblMessage.setForeground(new Color(255, 180, 180));
  218 + }
  219 + }
  220 +
  221 + protected void onShowDialog()
  222 + {
  223 + if (this.txtUsername.getText().length() > 0)
  224 + {
  225 + if (this.txtPassword.getText().length() > 0)
  226 + this.txtUsername.select(0, this.txtUsername.getText().length());
  227 + else
  228 + this.txtPassword.requestFocusInWindow();
  229 + }
  230 + }
  231 +
  232 + protected void onLoginClick()
  233 + {
  234 + this.dialogResult = true;
  235 + this.dialog.setVisible(false);
  236 + }
  237 +
  238 + protected void onCancelClick()
  239 + {
  240 + this.dialog.setVisible(false);
  241 + }
  242 +
  243 + protected void onOfflineCheckedChanged()
  244 + {
  245 + boolean selected = this.chkOffline.isSelected();
  246 + this.btnLogin.setText(selected ? "Work Offline" : "Log In");
  247 + this.txtUsername.setEnabled(!selected);
  248 + this.txtPassword.setEnabled(!selected);
  249 + }
  250 +
  251 + /**
  252 + * @param dialog
  253 + */
  254 + public void setDialog(JDialog dialog)
  255 + {
  256 + this.dialog = dialog;
  257 +
  258 + this.dialog.addWindowListener(new WindowAdapter()
  259 + {
  260 + @Override
  261 + public void windowOpened(WindowEvent e)
  262 + {
  263 + LoginPanel.this.onShowDialog();
  264 + }
  265 + });
  266 +
  267 + this.dialog.getRootPane().setDefaultButton(this.btnLogin);
  268 + this.dialog.setFocusTraversalPolicy(this.tabOrder);
  269 + }
  270 +
  271 + public boolean showModalDialog()
  272 + {
  273 + this.dialog.setVisible(true);
  274 + this.dialog.dispose();
  275 + return this.dialogResult;
  276 + }
  277 +
  278 + public String getUsername()
  279 + {
  280 + return this.txtUsername.getText();
  281 + }
  282 +
  283 + public String getPassword()
  284 + {
  285 + return this.txtPassword.getText();
  286 + }
  287 +
  288 + public boolean workOffline()
  289 + {
  290 + return this.chkOffline.isSelected();
  291 + }
  292 +
  293 + public static LoginPanel getLoginPanel(String username, String password, String error)
  294 + {
  295 + if (username == null) username = "";
  296 + if (password == null) password = "";
  297 +
  298 + final JDialog dialog = new JDialog();
  299 + final LoginPanel panel = new LoginPanel(username, password, error);
  300 + panel.setDialog(dialog);
  301 +
  302 + dialog.setContentPane(panel);
  303 + dialog.setTitle("Yggdrasil Login");
  304 + dialog.setResizable(false);
  305 + dialog.pack();
  306 + dialog.setDefaultCloseOperation(DISPOSE_ON_CLOSE);
  307 + dialog.setLocationRelativeTo(null);
  308 + dialog.setModal(true);
  309 +
  310 + return panel;
  311 + }
  312 +
  313 + class ListFocusTraversal extends FocusTraversalPolicy
  314 + {
  315 + private final List<Component> components = new ArrayList<Component>();
  316 +
  317 + void add(Component component)
  318 + {
  319 + this.components.add(component);
  320 + }
  321 +
  322 + @Override
  323 + public Component getComponentAfter(Container container, Component component)
  324 + {
  325 + int index = this.components.indexOf(component) + 1;
  326 + if (index >= this.components.size()) return this.components.get(0);
  327 + return this.components.get(index);
  328 + }
  329 +
  330 + @Override
  331 + public Component getComponentBefore(Container container, Component component)
  332 + {
  333 + int index = this.components.indexOf(component) - 1;
  334 + if (index < 0) return this.getLastComponent(container);
  335 + return this.components.get(index);
  336 + }
  337 +
  338 + @Override
  339 + public Component getFirstComponent(Container container)
  340 + {
  341 + return this.components.get(0);
  342 + }
  343 +
  344 + @Override
  345 + public Component getLastComponent(Container container)
  346 + {
  347 + return this.components.get(this.components.size() - 1);
  348 + }
  349 +
  350 + @Override
  351 + public Component getDefaultComponent(Container container)
  352 + {
  353 + return this.getFirstComponent(container);
  354 + }
  355 + }
  356 +}
... ...
debug/com/mumfrey/liteloader/debug/Start.java renamed to src/debug/java/com/mumfrey/liteloader/debug/Start.java
1   -package com.mumfrey.liteloader.debug;
2   -
3   -import java.io.File;
4   -import java.util.ArrayList;
5   -import java.util.HashMap;
6   -import java.util.HashSet;
7   -import java.util.List;
8   -import java.util.Map;
9   -import java.util.Map.Entry;
10   -import java.util.Set;
11   -
12   -import net.minecraft.launchwrapper.Launch;
13   -
14   -import com.google.common.base.Strings;
15   -import com.google.common.collect.ImmutableSet;
16   -import com.mumfrey.liteloader.launch.LiteLoaderTweaker;
17   -import com.mumfrey.liteloader.launch.LiteLoaderTweakerServer;
18   -import com.mumfrey.liteloader.util.log.LiteLoaderLogger;
19   -
20   -/**
21   - * Wrapper class for LaunchWrapper Main class, which logs in using Yggdrasil first so that online shizzle can be tested
22   - *
23   - * @author Adam Mummery-Smith
24   - */
25   -public abstract class Start
26   -{
27   - /**
28   - * Number of times to retry Yggdrasil login
29   - */
30   - private static final int LOGIN_RETRIES = 5;
31   -
32   - /**
33   - * Arguments which are allowed to have multiple occurrences
34   - */
35   - private static final Set<String> MULTI_VALUE_ARGS = ImmutableSet.<String>of(
36   - "--tweakClass"
37   - );
38   -
39   - /**
40   - * Entry point.
41   - *
42   - * @param args
43   - */
44   - public static void main(String[] args)
45   - {
46   - System.setProperty("mcpenv", "true");
47   - Launch.main(Start.processArgs(args));
48   - }
49   -
50   - /**
51   - * Process the launch-time args, since we may be being launched by GradleStart we need to parse
52   - * out any values passed in and ensure we replace them with our own
53   - */
54   - private static String[] processArgs(String[] args)
55   - {
56   - List<String> unqualifiedArgs = new ArrayList<String>();
57   - Map<String, Set<String>> qualifiedArgs = new HashMap<String, Set<String>>();
58   -
59   - Start.parseArgs(args, unqualifiedArgs, qualifiedArgs);
60   -
61   - if (Start.hasArg(unqualifiedArgs, "server"))
62   - {
63   - Start.addRequiredArgsServer(args, unqualifiedArgs, qualifiedArgs);
64   - }
65   - else
66   - {
67   - Start.addRequiredArgsClient(args, unqualifiedArgs, qualifiedArgs);
68   - }
69   -
70   - args = Start.combineArgs(args, unqualifiedArgs, qualifiedArgs);
71   -
72   - return args;
73   - }
74   -
75   - private static boolean hasArg(List<String> args, String target)
76   - {
77   - for (String arg : args)
78   - {
79   - if (target.equalsIgnoreCase(arg))
80   - return true;
81   - }
82   -
83   - return false;
84   - }
85   -
86   - /**
87   - * Read the args from the command line into the qualified and unqualified collections
88   - */
89   - private static void parseArgs(String[] args, List<String> unqualifiedArgs, Map<String, Set<String>> qualifiedArgs)
90   - {
91   - String qualifier = null;
92   - for (String arg : args)
93   - {
94   - boolean isQualifier = arg.startsWith("-");
95   -
96   - if (isQualifier)
97   - {
98   - if (qualifier != null) unqualifiedArgs.add(qualifier);
99   - qualifier = arg;
100   - }
101   - else if (qualifier != null)
102   - {
103   - Start.addArg(qualifiedArgs, qualifier, arg);
104   - qualifier = null;
105   - }
106   - else
107   - {
108   - unqualifiedArgs.add(arg);
109   - }
110   - }
111   -
112   - if (qualifier != null) unqualifiedArgs.add(qualifier);
113   - }
114   -
115   - private static void addRequiredArgsClient(String[] args, List<String> unqualifiedArgs, Map<String, Set<String>> qualifiedArgs)
116   - {
117   - LoginManager loginManager = Start.doLogin(qualifiedArgs);
118   -
119   - File gameDir = new File(System.getProperty("user.dir"));
120   - File assetsDir = new File(gameDir, "assets");
121   -
122   - Start.addArg(qualifiedArgs, "--tweakClass", LiteLoaderTweaker.class.getName());
123   - Start.addArg(qualifiedArgs, "--username", loginManager.getProfileName());
124   - Start.addArg(qualifiedArgs, "--uuid", loginManager.getUUID());
125   - Start.addArg(qualifiedArgs, "--accessToken", loginManager.getAuthenticatedToken());
126   - Start.addArg(qualifiedArgs, "--userType", loginManager.getUserType());
127   - Start.addArg(qualifiedArgs, "--userProperties", loginManager.getUserProperties());
128   - Start.addArg(qualifiedArgs, "--version", "mcp");
129   - Start.addArg(qualifiedArgs, "--gameDir", gameDir.getAbsolutePath());
130   - Start.addArg(qualifiedArgs, "--assetIndex", LiteLoaderTweaker.VERSION);
131   - Start.addArg(qualifiedArgs, "--assetsDir", assetsDir.getAbsolutePath());
132   - }
133   -
134   - private static void addRequiredArgsServer(String[] args, List<String> unqualifiedArgs, Map<String, Set<String>> qualifiedArgs)
135   - {
136   - File gameDir = new File(System.getProperty("user.dir"));
137   -
138   - Start.addArg(qualifiedArgs, "--tweakClass", LiteLoaderTweakerServer.class.getName());
139   - Start.addArg(qualifiedArgs, "--version", "mcp");
140   - Start.addArg(qualifiedArgs, "--gameDir", gameDir.getAbsolutePath());
141   - }
142   -
143   - private static LoginManager doLogin(Map<String, Set<String>> qualifiedArgs)
144   - {
145   - File loginJson = new File(new File(System.getProperty("user.dir")), ".auth.json");
146   - LoginManager loginManager = new LoginManager(loginJson);
147   -
148   - String usernameFromCmdLine = Start.getArg(qualifiedArgs, "--username");
149   - String passwordFromCmdLine = Start.getArg(qualifiedArgs, "--password");
150   -
151   - loginManager.login(usernameFromCmdLine, passwordFromCmdLine, Start.LOGIN_RETRIES);
152   -
153   - LiteLoaderLogger.info("Launching game as %s", loginManager.getProfileName());
154   -
155   - return loginManager;
156   - }
157   -
158   - private static void addArg(Map<String, Set<String>> qualifiedArgs, String qualifier, String arg)
159   - {
160   - Set<String> args = qualifiedArgs.get(qualifier);
161   -
162   - if (args == null)
163   - {
164   - args = new HashSet<String>();
165   - qualifiedArgs.put(qualifier, args);
166   - }
167   -
168   - if (!Start.MULTI_VALUE_ARGS.contains(qualifier))
169   - args.clear();
170   -
171   - args.add(arg);
172   - }
173   -
174   - private static String getArg(Map<String, Set<String>> qualifiedArgs, String arg)
175   - {
176   - if (qualifiedArgs.containsKey(arg))
177   - {
178   - return qualifiedArgs.get(arg).iterator().next();
179   - }
180   -
181   - return null;
182   - }
183   -
184   - private static String[] combineArgs(String[] args, List<String> unqualifiedArgs, Map<String, Set<String>> qualifiedArgs)
185   - {
186   - for (Entry<String, Set<String>> qualifiedArg : qualifiedArgs.entrySet())
187   - {
188   - for (String argValue : qualifiedArg.getValue())
189   - {
190   - unqualifiedArgs.add(qualifiedArg.getKey());
191   - if (!Strings.isNullOrEmpty(argValue)) unqualifiedArgs.add(argValue);
192   - }
193   - }
194   -
195   - return unqualifiedArgs.toArray(args);
196   - }
197   -}
  1 +package com.mumfrey.liteloader.debug;
  2 +
  3 +import java.io.File;
  4 +import java.util.ArrayList;
  5 +import java.util.HashMap;
  6 +import java.util.HashSet;
  7 +import java.util.List;
  8 +import java.util.Map;
  9 +import java.util.Map.Entry;
  10 +import java.util.Set;
  11 +
  12 +import net.minecraft.launchwrapper.Launch;
  13 +
  14 +import com.google.common.base.Strings;
  15 +import com.google.common.collect.ImmutableSet;
  16 +import com.mumfrey.liteloader.launch.LiteLoaderTweaker;
  17 +import com.mumfrey.liteloader.launch.LiteLoaderTweakerServer;
  18 +import com.mumfrey.liteloader.util.log.LiteLoaderLogger;
  19 +
  20 +/**
  21 + * Wrapper class for LaunchWrapper Main class, which logs in using Yggdrasil first so that online shizzle can be tested
  22 + *
  23 + * @author Adam Mummery-Smith
  24 + */
  25 +public abstract class Start
  26 +{
  27 + /**
  28 + * Number of times to retry Yggdrasil login
  29 + */
  30 + private static final int LOGIN_RETRIES = 5;
  31 +
  32 + /**
  33 + * Arguments which are allowed to have multiple occurrences
  34 + */
  35 + private static final Set<String> MULTI_VALUE_ARGS = ImmutableSet.<String>of(
  36 + "--tweakClass"
  37 + );
  38 +
  39 + /**
  40 + * Entry point.
  41 + *
  42 + * @param args
  43 + */
  44 + public static void main(String[] args)
  45 + {
  46 + System.setProperty("mcpenv", "true");
  47 + Launch.main(Start.processArgs(args));
  48 + }
  49 +
  50 + /**
  51 + * Process the launch-time args, since we may be being launched by GradleStart we need to parse
  52 + * out any values passed in and ensure we replace them with our own
  53 + */
  54 + private static String[] processArgs(String[] args)
  55 + {
  56 + List<String> unqualifiedArgs = new ArrayList<String>();
  57 + Map<String, Set<String>> qualifiedArgs = new HashMap<String, Set<String>>();
  58 +
  59 + Start.parseArgs(args, unqualifiedArgs, qualifiedArgs);
  60 +
  61 + if (Start.hasArg(unqualifiedArgs, "server"))
  62 + {
  63 + Start.addRequiredArgsServer(args, unqualifiedArgs, qualifiedArgs);
  64 + }
  65 + else
  66 + {
  67 + Start.addRequiredArgsClient(args, unqualifiedArgs, qualifiedArgs);
  68 + }
  69 +
  70 + args = Start.combineArgs(args, unqualifiedArgs, qualifiedArgs);
  71 +
  72 + return args;
  73 + }
  74 +
  75 + private static boolean hasArg(List<String> args, String target)
  76 + {
  77 + for (String arg : args)
  78 + {
  79 + if (target.equalsIgnoreCase(arg))
  80 + return true;
  81 + }
  82 +
  83 + return false;
  84 + }
  85 +
  86 + /**
  87 + * Read the args from the command line into the qualified and unqualified collections
  88 + */
  89 + private static void parseArgs(String[] args, List<String> unqualifiedArgs, Map<String, Set<String>> qualifiedArgs)
  90 + {
  91 + String qualifier = null;
  92 + for (String arg : args)
  93 + {
  94 + boolean isQualifier = arg.startsWith("-");
  95 +
  96 + if (isQualifier)
  97 + {
  98 + if (qualifier != null) unqualifiedArgs.add(qualifier);
  99 + qualifier = arg;
  100 + }
  101 + else if (qualifier != null)
  102 + {
  103 + Start.addArg(qualifiedArgs, qualifier, arg);
  104 + qualifier = null;
  105 + }
  106 + else
  107 + {
  108 + unqualifiedArgs.add(arg);
  109 + }
  110 + }
  111 +
  112 + if (qualifier != null) unqualifiedArgs.add(qualifier);
  113 + }
  114 +
  115 + private static void addRequiredArgsClient(String[] args, List<String> unqualifiedArgs, Map<String, Set<String>> qualifiedArgs)
  116 + {
  117 + LoginManager loginManager = Start.doLogin(qualifiedArgs);
  118 +
  119 + File gameDir = new File(System.getProperty("user.dir"));
  120 + File assetsDir = new File(gameDir, "assets");
  121 +
  122 + Start.addArg(qualifiedArgs, "--tweakClass", LiteLoaderTweaker.class.getName());
  123 + Start.addArg(qualifiedArgs, "--username", loginManager.getProfileName());
  124 + Start.addArg(qualifiedArgs, "--uuid", loginManager.getUUID());
  125 + Start.addArg(qualifiedArgs, "--accessToken", loginManager.getAuthenticatedToken());
  126 + Start.addArg(qualifiedArgs, "--userType", loginManager.getUserType());
  127 + Start.addArg(qualifiedArgs, "--userProperties", loginManager.getUserProperties());
  128 + Start.addArg(qualifiedArgs, "--version", "mcp");
  129 + Start.addArg(qualifiedArgs, "--gameDir", gameDir.getAbsolutePath());
  130 + Start.addArg(qualifiedArgs, "--assetIndex", LiteLoaderTweaker.VERSION);
  131 + Start.addArg(qualifiedArgs, "--assetsDir", assetsDir.getAbsolutePath());
  132 + }
  133 +
  134 + private static void addRequiredArgsServer(String[] args, List<String> unqualifiedArgs, Map<String, Set<String>> qualifiedArgs)
  135 + {
  136 + File gameDir = new File(System.getProperty("user.dir"));
  137 +
  138 + Start.addArg(qualifiedArgs, "--tweakClass", LiteLoaderTweakerServer.class.getName());
  139 + Start.addArg(qualifiedArgs, "--version", "mcp");
  140 + Start.addArg(qualifiedArgs, "--gameDir", gameDir.getAbsolutePath());
  141 + }
  142 +
  143 + private static LoginManager doLogin(Map<String, Set<String>> qualifiedArgs)
  144 + {
  145 + File loginJson = new File(new File(System.getProperty("user.dir")), ".auth.json");
  146 + LoginManager loginManager = new LoginManager(loginJson);
  147 +
  148 + String usernameFromCmdLine = Start.getArg(qualifiedArgs, "--username");
  149 + String passwordFromCmdLine = Start.getArg(qualifiedArgs, "--password");
  150 +
  151 + loginManager.login(usernameFromCmdLine, passwordFromCmdLine, Start.LOGIN_RETRIES);
  152 +
  153 + LiteLoaderLogger.info("Launching game as %s", loginManager.getProfileName());
  154 +
  155 + return loginManager;
  156 + }
  157 +
  158 + private static void addArg(Map<String, Set<String>> qualifiedArgs, String qualifier, String arg)
  159 + {
  160 + Set<String> args = qualifiedArgs.get(qualifier);
  161 +
  162 + if (args == null)
  163 + {
  164 + args = new HashSet<String>();
  165 + qualifiedArgs.put(qualifier, args);
  166 + }
  167 +
  168 + if (!Start.MULTI_VALUE_ARGS.contains(qualifier))
  169 + args.clear();
  170 +
  171 + args.add(arg);
  172 + }
  173 +
  174 + private static String getArg(Map<String, Set<String>> qualifiedArgs, String arg)
  175 + {
  176 + if (qualifiedArgs.containsKey(arg))
  177 + {
  178 + return qualifiedArgs.get(arg).iterator().next();
  179 + }
  180 +
  181 + return null;
  182 + }
  183 +
  184 + private static String[] combineArgs(String[] args, List<String> unqualifiedArgs, Map<String, Set<String>> qualifiedArgs)
  185 + {
  186 + for (Entry<String, Set<String>> qualifiedArg : qualifiedArgs.entrySet())
  187 + {
  188 + for (String argValue : qualifiedArg.getValue())
  189 + {
  190 + unqualifiedArgs.add(qualifiedArg.getKey());
  191 + if (!Strings.isNullOrEmpty(argValue)) unqualifiedArgs.add(argValue);
  192 + }
  193 + }
  194 +
  195 + return unqualifiedArgs.toArray(args);
  196 + }
  197 +}
... ...