Ticket #13318: patch-main-extract-argument-handling.patch
File patch-main-extract-argument-handling.patch, 58.6 KB (added by , 8 years ago) |
---|
-
src/org/openstreetmap/josm/Main.java
diff --git a/src/org/openstreetmap/josm/Main.java b/src/org/openstreetmap/josm/Main.java index c216556..b8a16dc 100644
a b import java.util.concurrent.ExecutionException; 36 36 import java.util.concurrent.ExecutorService; 37 37 import java.util.concurrent.Executors; 38 38 import java.util.concurrent.Future; 39 import java.util.logging.Handler;40 import java.util.logging.Level;41 import java.util.logging.LogRecord;42 import java.util.logging.Logger;43 39 44 40 import javax.swing.Action; 45 41 import javax.swing.InputMap; … … import org.openstreetmap.josm.data.projection.Projection; 76 72 import org.openstreetmap.josm.data.projection.ProjectionChangeListener; 77 73 import org.openstreetmap.josm.data.validation.OsmValidator; 78 74 import org.openstreetmap.josm.gui.GettingStarted; 79 import org.openstreetmap.josm.gui.MainApplication.Option;80 75 import org.openstreetmap.josm.gui.MainFrame; 81 76 import org.openstreetmap.josm.gui.MainMenu; 82 77 import org.openstreetmap.josm.gui.MainPanel; 83 78 import org.openstreetmap.josm.gui.MapFrame; 84 79 import org.openstreetmap.josm.gui.MapFrameListener; 80 import org.openstreetmap.josm.gui.ProgramArguments; 81 import org.openstreetmap.josm.gui.ProgramArguments.Option; 85 82 import org.openstreetmap.josm.gui.help.HelpUtil; 86 83 import org.openstreetmap.josm.gui.io.SaveLayersDialog; 87 84 import org.openstreetmap.josm.gui.layer.AbstractModifiableLayer; … … import org.openstreetmap.josm.plugins.PluginHandler; 108 105 import org.openstreetmap.josm.tools.CheckParameterUtil; 109 106 import org.openstreetmap.josm.tools.I18n; 110 107 import org.openstreetmap.josm.tools.ImageProvider; 108 import org.openstreetmap.josm.tools.Logging; 111 109 import org.openstreetmap.josm.tools.OpenBrowser; 112 110 import org.openstreetmap.josm.tools.OsmUrlToBounds; 113 111 import org.openstreetmap.josm.tools.PlatformHook; … … public abstract class Main { 223 221 224 222 protected static final Map<String, Throwable> NETWORK_ERRORS = new HashMap<>(); 225 223 226 // First lines of last 5 error and warning messages, used for bug reports227 private static final List<String> ERRORS_AND_WARNINGS = Collections.<String>synchronizedList(new ArrayList<String>());228 229 224 private static final Set<OnlineResource> OFFLINE_RESOURCES = EnumSet.noneOf(OnlineResource.class); 230 225 231 226 /** 232 227 * Logging level (5 = trace, 4 = debug, 3 = info, 2 = warn, 1 = error, 0 = none). 233 228 * @since 6248 229 * @deprecated Use {@link Logging} class. 234 230 */ 231 @Deprecated 235 232 public static int logLevel = 3; 236 233 237 234 /** … … public abstract class Main { 240 237 */ 241 238 protected static final MainPanel mainPanel = new MainPanel(getLayerManager()); 242 239 243 private static void rememberWarnErrorMsg(String msg) {244 // Only remember first line of message245 int idx = msg.indexOf('\n');246 if (idx > 0) {247 ERRORS_AND_WARNINGS.add(msg.substring(0, idx));248 } else {249 ERRORS_AND_WARNINGS.add(msg);250 }251 // Only keep 10 lines to avoid memory leak252 while (ERRORS_AND_WARNINGS.size() > 10) {253 ERRORS_AND_WARNINGS.remove(0);254 }255 }256 257 240 /** 258 241 * Replies the first lines of last 5 error and warning messages, used for bug reports 259 242 * @return the first lines of last 5 error and warning messages 260 243 * @since 7420 261 244 */ 262 245 public static final Collection<String> getLastErrorAndWarnings() { 263 return Collections.unmodifiableList(ERRORS_AND_WARNINGS);246 return Logging.getLastErrorAndWarnings(); 264 247 } 265 248 266 249 /** … … public abstract class Main { 268 251 * @since 8959 269 252 */ 270 253 public static void clearLastErrorAndWarnings() { 271 ERRORS_AND_WARNINGS.clear();254 Logging.clearLastErrorAndWarnings(); 272 255 } 273 256 274 257 /** … … public abstract class Main { 277 260 * @since 6248 278 261 */ 279 262 public static void error(String msg) { 280 if (logLevel < 1) 281 return; 282 if (msg != null && !msg.isEmpty()) { 283 System.err.println(tr("ERROR: {0}", msg)); 284 rememberWarnErrorMsg("E: "+msg); 285 } 263 Logging.error(msg); 286 264 } 287 265 288 266 /** … … public abstract class Main { 290 268 * @param msg The message to print. 291 269 */ 292 270 public static void warn(String msg) { 293 if (logLevel < 2) 294 return; 295 if (msg != null && !msg.isEmpty()) { 296 System.err.println(tr("WARNING: {0}", msg)); 297 rememberWarnErrorMsg("W: "+msg); 298 } 271 Logging.warn(msg); 299 272 } 300 273 301 274 /** … … public abstract class Main { 303 276 * @param msg The message to print. 304 277 */ 305 278 public static void info(String msg) { 306 if (logLevel < 3) 307 return; 308 if (msg != null && !msg.isEmpty()) { 309 System.out.println(tr("INFO: {0}", msg)); 310 } 279 Logging.info(msg); 311 280 } 312 281 313 282 /** … … public abstract class Main { 315 284 * @param msg The message to print. 316 285 */ 317 286 public static void debug(String msg) { 318 if (logLevel < 4) 319 return; 320 if (msg != null && !msg.isEmpty()) { 321 System.out.println(tr("DEBUG: {0}", msg)); 322 } 287 Logging.debug(msg); 323 288 } 324 289 325 290 /** … … public abstract class Main { 327 292 * @param msg The message to print. 328 293 */ 329 294 public static void trace(String msg) { 330 if (logLevel < 5) 331 return; 332 if (msg != null && !msg.isEmpty()) { 333 System.out.print("TRACE: "); 334 System.out.println(msg); 335 } 295 Logging.trace(msg); 336 296 } 337 297 338 298 /** … … public abstract class Main { 342 302 * @since 6852 343 303 */ 344 304 public static boolean isDebugEnabled() { 345 return logLevel >= 4;305 return Logging.isLoggingEnabled(Logging.LEVEL_DEBUG); 346 306 } 347 307 348 308 /** … … public abstract class Main { 352 312 * @since 6852 353 313 */ 354 314 public static boolean isTraceEnabled() { 355 return logLevel >= 5;315 return Logging.isLoggingEnabled(Logging.LEVEL_TRACE); 356 316 } 357 317 358 318 /** … … public abstract class Main { 363 323 * @since 6248 364 324 */ 365 325 public static void error(String msg, Object... objects) { 366 error(MessageFormat.format(msg, objects));326 Logging.error(msg, objects); 367 327 } 368 328 369 329 /** … … public abstract class Main { 373 333 * @param objects The objects to insert into format string. 374 334 */ 375 335 public static void warn(String msg, Object... objects) { 376 warn(MessageFormat.format(msg, objects));336 Logging.warn(msg, objects); 377 337 } 378 338 379 339 /** … … public abstract class Main { 383 343 * @param objects The objects to insert into format string. 384 344 */ 385 345 public static void info(String msg, Object... objects) { 386 info(MessageFormat.format(msg, objects));346 Logging.info(msg, objects); 387 347 } 388 348 389 349 /** … … public abstract class Main { 393 353 * @param objects The objects to insert into format string. 394 354 */ 395 355 public static void debug(String msg, Object... objects) { 396 debug(MessageFormat.format(msg, objects));356 Logging.debug(msg, objects); 397 357 } 398 358 399 359 /** … … public abstract class Main { 403 363 * @param objects The objects to insert into format string. 404 364 */ 405 365 public static void trace(String msg, Object... objects) { 406 trace(MessageFormat.format(msg, objects));366 Logging.trace(msg, objects); 407 367 } 408 368 409 369 /** … … public abstract class Main { 412 372 * @since 6248 413 373 */ 414 374 public static void error(Throwable t) { 415 error(t, true);375 Logging.logWithStackTrace(Logging.LEVEL_ERROR, t); 416 376 } 417 377 418 378 /** … … public abstract class Main { 421 381 * @since 6248 422 382 */ 423 383 public static void warn(Throwable t) { 424 warn(t, true);384 Logging.logWithStackTrace(Logging.LEVEL_WARN, t); 425 385 } 426 386 427 387 /** … … public abstract class Main { 430 390 * @since 10420 431 391 */ 432 392 public static void debug(Throwable t) { 433 debug(getErrorMessage(t));393 Logging.log(Logging.LEVEL_DEBUG, t); 434 394 } 435 395 436 396 /** … … public abstract class Main { 439 399 * @since 10420 440 400 */ 441 401 public static void trace(Throwable t) { 442 trace(getErrorMessage(t));402 Logging.log(Logging.LEVEL_TRACE, t); 443 403 } 444 404 445 405 /** … … public abstract class Main { 449 409 * @since 6642 450 410 */ 451 411 public static void error(Throwable t, boolean stackTrace) { 452 error(getErrorMessage(t));453 412 if (stackTrace) { 454 t.printStackTrace(); 413 Logging.log(Logging.LEVEL_ERROR, t); 414 } else { 415 Logging.logWithStackTrace(Logging.LEVEL_ERROR, t); 455 416 } 456 417 } 457 418 … … public abstract class Main { 462 423 * @since 10420 463 424 */ 464 425 public static void error(Throwable t, String message) { 465 warn(message + ' ' + getErrorMessage(t));426 Logging.log(Logging.LEVEL_ERROR, message, t); 466 427 } 467 428 468 429 /** … … public abstract class Main { 472 433 * @since 6642 473 434 */ 474 435 public static void warn(Throwable t, boolean stackTrace) { 475 warn(getErrorMessage(t));476 436 if (stackTrace) { 477 t.printStackTrace(); 437 Logging.log(Logging.LEVEL_WARN, t); 438 } else { 439 Logging.logWithStackTrace(Logging.LEVEL_WARN, t); 478 440 } 479 441 } 480 442 … … public abstract class Main { 485 447 * @since 10420 486 448 */ 487 449 public static void warn(Throwable t, String message) { 488 warn(message + ' ' + getErrorMessage(t));450 Logging.log(Logging.LEVEL_WARN, message, t); 489 451 } 490 452 491 453 /** … … public abstract class Main { 495 457 * @since 6642 496 458 */ 497 459 public static String getErrorMessage(Throwable t) { 498 if (t == null) { 499 return null; 500 } 501 StringBuilder sb = new StringBuilder(t.getClass().getName()); 502 String msg = t.getMessage(); 503 if (msg != null) { 504 sb.append(": ").append(msg.trim()); 505 } 506 Throwable cause = t.getCause(); 507 if (cause != null && !cause.equals(t)) { 508 sb.append(". ").append(tr("Cause: ")).append(getErrorMessage(cause)); 509 } 510 return sb.toString(); 460 return Logging.getErrorMessage(t); 511 461 } 512 462 513 463 /** … … public abstract class Main { 590 540 isOpenjdk = System.getProperty("java.vm.name").toUpperCase(Locale.ENGLISH).indexOf("OPENJDK") != -1; 591 541 fileWatcher.start(); 592 542 593 new InitializationTask(tr("Executing platform startup hook")) { 594 @Override 595 public void initialize() { 596 platform.startupHook(); 597 } 598 }.call(); 543 new InitializationTask(tr("Executing platform startup hook"), platform::startupHook).call(); 599 544 600 new InitializationTask(tr("Building main menu")) { 601 602 @Override 603 public void initialize() { 604 initializeMainWindow(); 605 } 606 }.call(); 545 new InitializationTask(tr("Building main menu"), this::initializeMainWindow).call(); 607 546 608 547 undoRedo.addCommandQueueListener(redoUndoListener); 609 548 … … public abstract class Main { 616 555 // contains several initialization tasks to be executed (in parallel) by a ExecutorService 617 556 List<Callable<Void>> tasks = new ArrayList<>(); 618 557 619 tasks.add(new InitializationTask(tr("Initializing OSM API")) { 620 621 @Override 622 public void initialize() { 558 tasks.add(new InitializationTask(tr("Initializing OSM API"), () -> { 623 559 // We try to establish an API connection early, so that any API 624 560 // capabilities are already known to the editor instance. However 625 561 // if it goes wrong that's not critical at this stage. … … public abstract class Main { 628 564 } catch (OsmTransferCanceledException | OsmApiInitializationException e) { 629 565 Main.warn(getErrorMessage(Utils.getRootCause(e))); 630 566 } 631 } 632 }); 633 634 tasks.add(new InitializationTask(tr("Initializing validator")) { 567 })); 635 568 636 @Override 637 public void initialize() { 638 OsmValidator.initialize(); 639 } 640 }); 569 tasks.add(new InitializationTask(tr("Initializing validator"), OsmValidator::initialize)); 641 570 642 tasks.add(new InitializationTask(tr("Initializing presets") ) {571 tasks.add(new InitializationTask(tr("Initializing presets"), TaggingPresets::initialize)); 643 572 644 @Override 645 public void initialize() { 646 TaggingPresets.initialize(); 647 } 648 }); 573 tasks.add(new InitializationTask(tr("Initializing map styles"), MapPaintPreference::initialize)); 649 574 650 tasks.add(new InitializationTask(tr("Initializing map styles")) { 651 652 @Override 653 public void initialize() { 654 MapPaintPreference.initialize(); 655 } 656 }); 657 658 tasks.add(new InitializationTask(tr("Loading imagery preferences")) { 659 660 @Override 661 public void initialize() { 662 ImageryPreference.initialize(); 663 } 664 }); 575 tasks.add(new InitializationTask(tr("Loading imagery preferences"), ImageryPreference::initialize)); 665 576 666 577 try { 667 finalExecutorService service = Executors.newFixedThreadPool(578 ExecutorService service = Executors.newFixedThreadPool( 668 579 Runtime.getRuntime().availableProcessors(), Utils.newThreadFactory("main-init-%d", Thread.NORM_PRIORITY)); 669 580 for (Future<Void> i : service.invokeAll(tasks)) { 670 581 i.get(); … … public abstract class Main { 677 588 // hooks for the jmapviewer component 678 589 FeatureAdapter.registerBrowserAdapter(OpenBrowser::displayUrl); 679 590 FeatureAdapter.registerTranslationAdapter(I18n.getTranslationAdapter()); 680 FeatureAdapter.registerLoggingAdapter(name -> { 681 Logger logger = Logger.getAnonymousLogger(); 682 logger.setUseParentHandlers(false); 683 logger.setLevel(Level.ALL); 684 if (logger.getHandlers().length == 0) { 685 logger.addHandler(new Handler() { 686 @Override 687 public void publish(LogRecord record) { 688 String msg = MessageFormat.format(record.getMessage(), record.getParameters()); 689 if (record.getLevel().intValue() >= Level.SEVERE.intValue()) { 690 Main.error(msg); 691 } else if (record.getLevel().intValue() >= Level.WARNING.intValue()) { 692 Main.warn(msg); 693 } else if (record.getLevel().intValue() >= Level.INFO.intValue()) { 694 Main.info(msg); 695 } else if (record.getLevel().intValue() >= Level.FINE.intValue()) { 696 Main.debug(msg); 697 } else { 698 Main.trace(msg); 699 } 700 } 701 702 @Override 703 public void flush() { 704 // Do nothing 705 } 706 707 @Override 708 public void close() { 709 // Do nothing 710 } 711 }); 712 } 713 return logger; 714 }); 591 FeatureAdapter.registerLoggingAdapter(name -> Logging.getLogger()); 715 592 716 new InitializationTask(tr("Updating user interface")) { 717 718 @Override 719 public void initialize() { 720 toolbar.refreshToolbarControl(); 721 toolbar.control.updateUI(); 722 contentPanePrivate.updateUI(); 723 } 724 }.call(); 593 new InitializationTask(tr("Updating user interface"), () -> { 594 toolbar.refreshToolbarControl(); 595 toolbar.control.updateUI(); 596 contentPanePrivate.updateUI(); 597 }).call(); 725 598 } 726 599 727 600 /** … … public abstract class Main { 732 605 // can be implementd by subclasses 733 606 } 734 607 735 private abstractstatic class InitializationTask implements Callable<Void> {608 private static class InitializationTask implements Callable<Void> { 736 609 737 610 private final String name; 611 private Runnable task; 738 612 739 protected InitializationTask(String name ) {613 protected InitializationTask(String name, Runnable task) { 740 614 this.name = name; 615 this.task = task; 741 616 } 742 617 743 public abstract void initialize();744 745 618 @Override 746 619 public Void call() { 747 620 Object status = null; 748 621 if (initListener != null) { 749 622 status = initListener.updateStatus(name); 750 623 } 751 initialize();624 task.run(); 752 625 if (initListener != null) { 753 626 initListener.finish(status); 754 627 } … … public abstract class Main { 970 843 * Should be called before the main constructor to setup some parameter stuff 971 844 * @param args The parsed argument list. 972 845 */ 973 public static void preConstructorInit( Map<Option, Collection<String>>args) {846 public static void preConstructorInit(ProgramArguments args) { 974 847 ProjectionPreference.setProjection(); 975 848 976 849 String defaultlaf = platform.getDefaultStyle(); … … public abstract class Main { 1037 910 } 1038 911 } 1039 912 1040 protected static void postConstructorProcessCmdLine(Map<Option, Collection<String>> args) { 1041 if (args.containsKey(Option.DOWNLOAD)) { 1042 List<File> fileList = new ArrayList<>(); 1043 for (String s : args.get(Option.DOWNLOAD)) { 1044 DownloadParamType.paramType(s).download(s, fileList); 1045 } 1046 if (!fileList.isEmpty()) { 1047 OpenFileAction.openFiles(fileList, true); 1048 } 913 protected static void postConstructorProcessCmdLine(ProgramArguments args) { 914 List<File> fileList = new ArrayList<>(); 915 for (String s : args.get(Option.DOWNLOAD)) { 916 DownloadParamType.paramType(s).download(s, fileList); 1049 917 } 1050 if (args.containsKey(Option.DOWNLOADGPS)) { 1051 for (String s : args.get(Option.DOWNLOADGPS)) { 1052 DownloadParamType.paramType(s).downloadGps(s); 1053 } 918 if (!fileList.isEmpty()) { 919 OpenFileAction.openFiles(fileList, true); 1054 920 } 1055 if (args.containsKey(Option.SELECTION)) { 1056 for (String s : args.get(Option.SELECTION)) { 1057 SearchAction.search(s, SearchAction.SearchMode.add); 1058 } 921 for (String s : args.get(Option.DOWNLOADGPS)) { 922 DownloadParamType.paramType(s).downloadGps(s); 923 } 924 for (String s : args.get(Option.SELECTION)) { 925 SearchAction.search(s, SearchAction.SearchMode.add); 1059 926 } 1060 927 } 1061 928 … … public abstract class Main { 1547 1414 public static void setup() { 1548 1415 if (!windowSwitchListeners.isEmpty()) { 1549 1416 for (Window w : Window.getWindows()) { 1550 if (w.isShowing()) { 1551 if (!Arrays.asList(w.getWindowListeners()).contains(getInstance())) { 1552 w.addWindowListener(getInstance()); 1553 } 1417 if (w.isShowing() && !Arrays.asList(w.getWindowListeners()).contains(getInstance())) { 1418 w.addWindowListener(getInstance()); 1554 1419 } 1555 1420 } 1556 1421 } -
src/org/openstreetmap/josm/gui/MainApplication.java
diff --git a/src/org/openstreetmap/josm/gui/MainApplication.java b/src/org/openstreetmap/josm/gui/MainApplication.java index f58a661..d3fb110 100644
a b import java.security.PermissionCollection; 24 24 import java.security.Permissions; 25 25 import java.security.Policy; 26 26 import java.security.cert.CertificateException; 27 import java.util.ArrayList;28 27 import java.util.Arrays; 29 28 import java.util.Collection; 30 import java.util.EnumMap;31 29 import java.util.List; 32 30 import java.util.Locale; 33 import java.util. Map;31 import java.util.Optional; 34 32 import java.util.Set; 35 33 import java.util.TreeSet; 34 import java.util.logging.Level; 36 35 37 36 import javax.swing.JOptionPane; 38 37 import javax.swing.RepaintManager; … … import org.openstreetmap.josm.actions.RestartAction; 45 44 import org.openstreetmap.josm.data.AutosaveTask; 46 45 import org.openstreetmap.josm.data.CustomConfigurator; 47 46 import org.openstreetmap.josm.data.Version; 47 import org.openstreetmap.josm.gui.ProgramArguments.Option; 48 48 import org.openstreetmap.josm.gui.SplashScreen.SplashProgressMonitor; 49 49 import org.openstreetmap.josm.gui.download.DownloadDialog; 50 50 import org.openstreetmap.josm.gui.preferences.server.OAuthAccessTokenHolder; … … import org.openstreetmap.josm.plugins.PluginInformation; 62 62 import org.openstreetmap.josm.tools.FontsManager; 63 63 import org.openstreetmap.josm.tools.HttpClient; 64 64 import org.openstreetmap.josm.tools.I18n; 65 import org.openstreetmap.josm.tools.Logging; 65 66 import org.openstreetmap.josm.tools.OsmUrlToBounds; 66 67 import org.openstreetmap.josm.tools.PlatformHookWindows; 67 68 import org.openstreetmap.josm.tools.Utils; 68 69 import org.openstreetmap.josm.tools.WindowGeometry; 70 import org.openstreetmap.josm.tools.bugreport.BugReport; 69 71 import org.openstreetmap.josm.tools.bugreport.BugReportExceptionHandler; 70 72 71 import gnu.getopt.Getopt;72 import gnu.getopt.LongOpt;73 74 73 /** 75 74 * Main window class application. 76 75 * … … public class MainApplication extends Main { 170 169 } 171 170 172 171 /** 173 * JOSM command line options.174 * @see <a href="https://josm.openstreetmap.de/wiki/Help/CommandLineOptions">Help/CommandLineOptions</a>175 * @since 5279176 */177 public enum Option {178 /** --help|-h Show this help */179 HELP(false),180 /** --version Displays the JOSM version and exits */181 VERSION(false),182 /** --debug Print debugging messages to console */183 DEBUG(false),184 /** --trace Print detailed debugging messages to console */185 TRACE(false),186 /** --language=<language> Set the language */187 LANGUAGE(true),188 /** --reset-preferences Reset the preferences to default */189 RESET_PREFERENCES(false),190 /** --load-preferences=<url-to-xml> Changes preferences according to the XML file */191 LOAD_PREFERENCES(true),192 /** --set=<key>=<value> Set preference key to value */193 SET(true),194 /** --geometry=widthxheight(+|-)x(+|-)y Standard unix geometry argument */195 GEOMETRY(true),196 /** --no-maximize Do not launch in maximized mode */197 NO_MAXIMIZE(false),198 /** --maximize Launch in maximized mode */199 MAXIMIZE(false),200 /** --download=minlat,minlon,maxlat,maxlon Download the bounding box <br>201 * --download=<URL> Download the location at the URL (with lat=x&lon=y&zoom=z) <br>202 * --download=<filename> Open a file (any file type that can be opened with File/Open) */203 DOWNLOAD(true),204 /** --downloadgps=minlat,minlon,maxlat,maxlon Download the bounding box as raw GPS <br>205 * --downloadgps=<URL> Download the location at the URL (with lat=x&lon=y&zoom=z) as raw GPS */206 DOWNLOADGPS(true),207 /** --selection=<searchstring> Select with the given search */208 SELECTION(true),209 /** --offline=<osm_api|josm_website|all> Disable access to the given resource(s), delimited by comma */210 OFFLINE(true),211 /** --skip-plugins */212 SKIP_PLUGINS(false);213 214 private final String name;215 private final boolean requiresArg;216 217 Option(boolean requiresArgument) {218 this.name = name().toLowerCase(Locale.ENGLISH).replace('_', '-');219 this.requiresArg = requiresArgument;220 }221 222 /**223 * Replies the option name224 * @return The option name, in lowercase225 */226 public String getName() {227 return name;228 }229 230 /**231 * Determines if this option requires an argument.232 * @return {@code true} if this option requires an argument, {@code false} otherwise233 */234 public boolean requiresArgument() {235 return requiresArg;236 }237 }238 239 /**240 * Builds the command-line argument map.241 * @param args command-line arguments array242 * @return command-line argument map243 */244 public static Map<Option, Collection<String>> buildCommandLineArgumentMap(String ... args) {245 246 List<LongOpt> los = new ArrayList<>();247 for (Option o : Option.values()) {248 los.add(new LongOpt(o.getName(), o.requiresArgument() ? LongOpt.REQUIRED_ARGUMENT : LongOpt.NO_ARGUMENT, null, 0));249 }250 251 Getopt g = new Getopt("JOSM", args, "hv", los.toArray(new LongOpt[los.size()]));252 253 Map<Option, Collection<String>> argMap = new EnumMap<>(Option.class);254 255 int c;256 while ((c = g.getopt()) != -1) {257 Option opt;258 switch (c) {259 case 'h':260 opt = Option.HELP;261 break;262 case 'v':263 opt = Option.VERSION;264 break;265 case 0:266 opt = Option.values()[g.getLongind()];267 break;268 default:269 opt = null;270 }271 if (opt != null) {272 Collection<String> values = argMap.get(opt);273 if (values == null) {274 values = new ArrayList<>();275 argMap.put(opt, values);276 }277 values.add(g.getOptarg());278 } else279 throw new IllegalArgumentException("Invalid option: "+c);280 }281 // positional arguments are a shortcut for the --download ... option282 for (int i = g.getOptind(); i < args.length; ++i) {283 Collection<String> values = argMap.get(Option.DOWNLOAD);284 if (values == null) {285 values = new ArrayList<>();286 argMap.put(Option.DOWNLOAD, values);287 }288 values.add(args[i]);289 }290 291 return argMap;292 }293 294 /**295 172 * Main application Startup 296 173 * @param argArray Command-line arguments 297 174 */ … … public class MainApplication extends Main { 300 177 Main.checkJavaVersion(); 301 178 302 179 // construct argument table 303 Map<Option, Collection<String>>args = null;180 ProgramArguments args = null; 304 181 try { 305 args = buildCommandLineArgumentMap(argArray);182 args = new ProgramArguments(argArray); 306 183 } catch (IllegalArgumentException e) { 307 184 System.exit(1); 308 185 return; 309 186 } 310 187 311 final boolean languageGiven = args.containsKey(Option.LANGUAGE); 188 Level logLevel = args.getLogLevel(); 189 Logging.setLogLevel(logLevel); 190 Main.info(tr("Log level is at ", logLevel)); 312 191 313 if (languageGiven) { 314 I18n.set(args.get(Option.LANGUAGE).iterator().next()); 315 } 192 Optional<String> language = args.getSingle(Option.LANGUAGE); 193 I18n.set(language.orElse(null)); 316 194 317 195 initApplicationPreferences(); 318 196 … … public class MainApplication extends Main { 340 218 341 219 Main.COMMAND_LINE_ARGS.addAll(Arrays.asList(argArray)); 342 220 343 if (args. containsKey(Option.VERSION)) {221 if (args.showVersion()) { 344 222 System.out.println(Version.getInstance().getAgentString()); 345 223 System.exit(0); 346 } 347 348 if (args.containsKey(Option.DEBUG) || args.containsKey(Option.TRACE)) { 349 // Enable JOSM debug level 350 logLevel = 4; 351 Main.info(tr("Printing debugging messages to console")); 224 } else if (args.showHelp()) { 225 showHelp(); 226 System.exit(0); 352 227 } 353 228 354 229 boolean skipLoadingPlugins = false; 355 if (args. containsKey(Option.SKIP_PLUGINS)) {230 if (args.hasOption(Option.SKIP_PLUGINS)) { 356 231 skipLoadingPlugins = true; 357 232 Main.info(tr("Plugin loading skipped")); 358 233 } 359 234 360 if (args.containsKey(Option.TRACE)) { 361 // Enable JOSM debug level 362 logLevel = 5; 235 if (Logging.isLoggingEnabled(Logging.LEVEL_TRACE)) { 363 236 // Enable debug in OAuth signpost via system preference, but only at trace level 364 237 Utils.updateSystemProperty("debug", "true"); 365 238 Main.info(tr("Enabled detailed debug level (trace)")); 366 239 } 367 240 368 Main.pref.init(args. containsKey(Option.RESET_PREFERENCES));241 Main.pref.init(args.hasOption(Option.RESET_PREFERENCES)); 369 242 370 if (args.containsKey(Option.SET)) { 371 for (String i : args.get(Option.SET)) { 372 String[] kv = i.split("=", 2); 373 Main.pref.put(kv[0], "null".equals(kv[1]) ? null : kv[1]); 374 } 375 } 243 args.getPreferencesToSet().forEach(Main.pref::put); 376 244 377 if (!language Given) {245 if (!language.isPresent()) { 378 246 I18n.set(Main.pref.get("language", null)); 379 247 } 380 248 Main.pref.updateSystemProperties(); … … public class MainApplication extends Main { 382 250 checkIPv6(); 383 251 384 252 // asking for help? show help and exit 385 if (args. containsKey(Option.HELP)) {253 if (args.hasOption(Option.HELP)) { 386 254 showHelp(); 387 255 System.exit(0); 388 256 } … … public class MainApplication extends Main { 396 264 I18n.setupLanguageFonts(); 397 265 398 266 WindowGeometry geometry = WindowGeometry.mainWindow("gui.geometry", 399 args. containsKey(Option.GEOMETRY) ? args.get(Option.GEOMETRY).iterator().next() : null,400 !args. containsKey(Option.NO_MAXIMIZE) && Main.pref.getBoolean("gui.maximized", false));267 args.getSingle(Option.GEOMETRY).orElse(null), 268 !args.hasOption(Option.NO_MAXIMIZE) && Main.pref.getBoolean("gui.maximized", false)); 401 269 final MainFrame mainFrame = new MainFrame(contentPanePrivate, mainPanel, geometry); 402 270 Main.parent = mainFrame; 403 271 404 if (args. containsKey(Option.LOAD_PREFERENCES)) {272 if (args.hasOption(Option.LOAD_PREFERENCES)) { 405 273 CustomConfigurator.XMLCommandProcessor config = new CustomConfigurator.XMLCommandProcessor(Main.pref); 406 274 for (String i : args.get(Option.LOAD_PREFERENCES)) { 407 275 info("Reading preferences from " + i); 408 276 try (InputStream is = HttpClient.create(new URL(i)).connect().getContent()) { 409 277 config.openAndReadXML(is); 410 278 } catch (IOException ex) { 411 throw new RuntimeException(ex);279 throw BugReport.intercept(ex).put("file", i); 412 280 } 413 281 } 414 282 } … … public class MainApplication extends Main { 471 339 Main.MasterWindowListener.setup(); 472 340 473 341 boolean maximized = Main.pref.getBoolean("gui.maximized", false); 474 if ((!args. containsKey(Option.NO_MAXIMIZE) && maximized) || args.containsKey(Option.MAXIMIZE)) {342 if ((!args.hasOption(Option.NO_MAXIMIZE) && maximized) || args.hasOption(Option.MAXIMIZE)) { 475 343 mainFrame.setMaximized(true); 476 344 } 477 345 if (main.menu.fullscreenToggleAction != null) { … … public class MainApplication extends Main { 529 397 toolbar.refreshToolbarControl(); 530 398 } 531 399 532 private static void processOffline( Map<Option, Collection<String>>args) {533 if (args.containsKey(Option.OFFLINE)) {534 for (String s : args.get(Option.OFFLINE).iterator().next().split(",")) {400 private static void processOffline(ProgramArguments args) { 401 for (String offlineNames : args.get(Option.OFFLINE)) { 402 for (String s : offlineNames.split(",")) { 535 403 try { 536 404 Main.setOffline(OnlineResource.valueOf(s.toUpperCase(Locale.ENGLISH))); 537 405 } catch (IllegalArgumentException e) { … … public class MainApplication extends Main { 541 409 return; 542 410 } 543 411 } 544 Set<OnlineResource> offline = Main.getOfflineResources();545 if (!offline.isEmpty()) {546 Main.warn(trn("JOSM is running in offline mode. This resource will not be available: {0}",547 "JOSM is running in offline mode. These resourceswill not be available: {0}",548 offline.size(), offline.size() == 1 ? offline.iterator().next() : Arrays.toString(offline.toArray())));549 }412 } 413 Set<OnlineResource> offline = Main.getOfflineResources(); 414 if (!offline.isEmpty()) { 415 Main.warn(trn("JOSM is running in offline mode. This resource will not be available: {0}", 416 "JOSM is running in offline mode. These resources will not be available: {0}", 417 offline.size(), offline.size() == 1 ? offline.iterator().next() : Arrays.toString(offline.toArray()))); 550 418 } 551 419 } 552 420 … … public class MainApplication extends Main { 601 469 602 470 private static class GuiFinalizationWorker implements Runnable { 603 471 604 private final Map<Option, Collection<String>>args;472 private final ProgramArguments args; 605 473 private final DefaultProxySelector proxySelector; 606 474 607 GuiFinalizationWorker( Map<Option, Collection<String>>args, DefaultProxySelector proxySelector) {475 GuiFinalizationWorker(ProgramArguments args, DefaultProxySelector proxySelector) { 608 476 this.args = args; 609 477 this.proxySelector = proxySelector; 610 478 } -
new file src/org/openstreetmap/josm/gui/ProgramArguments.java
diff --git a/src/org/openstreetmap/josm/gui/ProgramArguments.java b/src/org/openstreetmap/josm/gui/ProgramArguments.java new file mode 100644 index 0000000..cf446f2
- + 1 // License: GPL. For details, see LICENSE file. 2 package org.openstreetmap.josm.gui; 3 4 import java.util.ArrayList; 5 import java.util.Collection; 6 import java.util.Collections; 7 import java.util.EnumMap; 8 import java.util.HashMap; 9 import java.util.List; 10 import java.util.Locale; 11 import java.util.Map; 12 import java.util.Optional; 13 import java.util.logging.Level; 14 import java.util.stream.Stream; 15 16 import org.openstreetmap.josm.tools.Logging; 17 18 import gnu.getopt.Getopt; 19 import gnu.getopt.LongOpt; 20 21 /** 22 * This class holds the arguments passed on to Main. 23 * @author Michael Zangl 24 * @since xxx 25 */ 26 public class ProgramArguments { 27 28 /** 29 * JOSM command line options. 30 * @see <a href="https://josm.openstreetmap.de/wiki/Help/CommandLineOptions">Help/CommandLineOptions</a> 31 * @since xxx 32 */ 33 public enum Option { 34 /** --help|-h Show this help */ 35 HELP(false), 36 /** --version Displays the JOSM version and exits */ 37 VERSION(false), 38 /** --debug Print debugging messages to console */ 39 DEBUG(false), 40 /** --trace Print detailed debugging messages to console */ 41 TRACE(false), 42 /** --language=<language> Set the language */ 43 LANGUAGE(true), 44 /** --reset-preferences Reset the preferences to default */ 45 RESET_PREFERENCES(false), 46 /** --load-preferences=<url-to-xml> Changes preferences according to the XML file */ 47 LOAD_PREFERENCES(true), 48 /** --set=<key>=<value> Set preference key to value */ 49 SET(true), 50 /** --geometry=widthxheight(+|-)x(+|-)y Standard unix geometry argument */ 51 GEOMETRY(true), 52 /** --no-maximize Do not launch in maximized mode */ 53 NO_MAXIMIZE(false), 54 /** --maximize Launch in maximized mode */ 55 MAXIMIZE(false), 56 /** --download=minlat,minlon,maxlat,maxlon Download the bounding box <br> 57 * --download=<URL> Download the location at the URL (with lat=x&lon=y&zoom=z) <br> 58 * --download=<filename> Open a file (any file type that can be opened with File/Open) */ 59 DOWNLOAD(true), 60 /** --downloadgps=minlat,minlon,maxlat,maxlon Download the bounding box as raw GPS <br> 61 * --downloadgps=<URL> Download the location at the URL (with lat=x&lon=y&zoom=z) as raw GPS */ 62 DOWNLOADGPS(true), 63 /** --selection=<searchstring> Select with the given search */ 64 SELECTION(true), 65 /** --offline=<osm_api|josm_website|all> Disable access to the given resource(s), delimited by comma */ 66 OFFLINE(true), 67 /** --skip-plugins */ 68 SKIP_PLUGINS(false); 69 70 private final String name; 71 private final boolean requiresArg; 72 73 Option(boolean requiresArgument) { 74 this.name = name().toLowerCase(Locale.ENGLISH).replace('_', '-'); 75 this.requiresArg = requiresArgument; 76 } 77 78 /** 79 * Replies the option name 80 * @return The option name, in lowercase 81 */ 82 public String getName() { 83 return name; 84 } 85 86 /** 87 * Determines if this option requires an argument. 88 * @return {@code true} if this option requires an argument, {@code false} otherwise 89 */ 90 public boolean requiresArgument() { 91 return requiresArg; 92 } 93 94 LongOpt toLongOpt() { 95 return new LongOpt(getName(), requiresArgument() ? LongOpt.REQUIRED_ARGUMENT : LongOpt.NO_ARGUMENT, null, 0); 96 } 97 } 98 99 private final Map<Option, List<String>> argMap = new EnumMap<>(Option.class); 100 101 /** 102 * Construct the program arguments object 103 * @param args The args passed to main. 104 */ 105 public ProgramArguments(String[] args) { 106 Stream.of(Option.values()).forEach(o -> argMap.put(o, new ArrayList<>())); 107 108 buildCommandLineArgumentMap(args); 109 } 110 111 /** 112 * Builds the command-line argument map. 113 * @param args command-line arguments array 114 */ 115 private void buildCommandLineArgumentMap(String ... args) { 116 LongOpt[] los = Stream.of(Option.values()).map(Option::toLongOpt).toArray(i -> new LongOpt[i]); 117 118 Getopt g = new Getopt("JOSM", args, "hv", los); 119 120 int c; 121 while ((c = g.getopt()) != -1) { 122 Option opt; 123 switch (c) { 124 case 'h': 125 opt = Option.HELP; 126 break; 127 case 'v': 128 opt = Option.VERSION; 129 break; 130 case 0: 131 opt = Option.values()[g.getLongind()]; 132 break; 133 default: 134 opt = null; 135 } 136 if (opt != null) { 137 addOption(opt, g.getOptarg()); 138 } else 139 throw new IllegalArgumentException("Invalid option: "+c); 140 } 141 // positional arguments are a shortcut for the --download ... option 142 for (int i = g.getOptind(); i < args.length; ++i) { 143 addOption(Option.DOWNLOAD, args[i]); 144 } 145 } 146 147 private void addOption(Option opt, String optarg) { 148 argMap.get(opt).add(optarg); 149 } 150 151 /** 152 * Gets a single argument (the first) that was given for the given option. 153 * @param option The option to search 154 * @return The argument as optional value. 155 */ 156 public Optional<String> getSingle(Option option) { 157 return get(option).stream().findFirst(); 158 } 159 160 /** 161 * Gets all values that are given for a given option 162 * @param option The option 163 * @return The values that were given. May be empty. 164 */ 165 public Collection<String> get(Option option) { 166 return Collections.unmodifiableList(argMap.get(option)); 167 } 168 169 /** 170 * Test if a given option was used by the user. 171 * @param option The option to test for 172 * @return <code>true</code> if the user used it. 173 */ 174 public boolean hasOption(Option option) { 175 return !get(option).isEmpty(); 176 } 177 178 /** 179 * Helper method to indicate if version should be displayed. 180 * @return <code>true</code> to display version 181 */ 182 public boolean showVersion() { 183 return hasOption(Option.VERSION); 184 } 185 186 /** 187 * Helper method to indicate if help should be displayed. 188 * @return <code>true</code> to display version 189 */ 190 public boolean showHelp() { 191 return !get(Option.HELP).isEmpty(); 192 } 193 194 /** 195 * Get the log level the user wants us to use. 196 * @return The log level. 197 */ 198 public Level getLogLevel() { 199 if (hasOption(Option.TRACE)) { 200 return Logging.LEVEL_TRACE; 201 } else if (hasOption(Option.DEBUG)) { 202 return Logging.LEVEL_DEBUG; 203 } else { 204 return Logging.LEVEL_INFO; 205 } 206 } 207 208 /** 209 * Gets a map of all preferences the user wants to set. 210 * @return The preferences to set. It contains null values for preferences to unset 211 */ 212 public Map<String, String> getPreferencesToSet() { 213 HashMap<String, String> map = new HashMap<>(); 214 get(Option.SET).stream().map(i -> i.split("=", 2)).forEach(kv -> map.put(kv[0], getValue(kv))); 215 return map; 216 } 217 218 private static String getValue(String[] kv) { 219 if (kv.length < 2) { 220 return ""; 221 } else if ("null".equals(kv[1])) { 222 return null; 223 } else { 224 return kv[1]; 225 } 226 } 227 } -
new file src/org/openstreetmap/josm/tools/Logging.java
diff --git a/src/org/openstreetmap/josm/tools/Logging.java b/src/org/openstreetmap/josm/tools/Logging.java new file mode 100644 index 0000000..db6855f
- + 1 // License: GPL. For details, see LICENSE file. 2 package org.openstreetmap.josm.tools; 3 4 import static org.openstreetmap.josm.tools.I18n.tr; 5 6 import java.io.OutputStream; 7 import java.io.PrintWriter; 8 import java.io.StringWriter; 9 import java.text.MessageFormat; 10 import java.util.ArrayList; 11 import java.util.Arrays; 12 import java.util.List; 13 import java.util.function.Supplier; 14 import java.util.logging.ConsoleHandler; 15 import java.util.logging.Handler; 16 import java.util.logging.Level; 17 import java.util.logging.LogRecord; 18 import java.util.logging.Logger; 19 20 import org.openstreetmap.josm.tools.bugreport.BugReport; 21 22 /** 23 * This class contains utility methods to log errors and warnings. 24 * <p> 25 * There are multiple log levels supported. 26 * @author Michael Zangl 27 * @since xxx 28 */ 29 public final class Logging { 30 /** 31 * The josm internal log level indicating a severe error in the application that usually leads to a crash. 32 */ 33 public static final Level LEVEL_ERROR = Level.SEVERE; 34 /** 35 * The josm internal log level to use when something that may lead to a crash or wrong behaviour has happened. 36 */ 37 public static final Level LEVEL_WARN = Level.WARNING; 38 /** 39 * The josm internal log level to use for important events that will be useful when debugging problems 40 */ 41 public static final Level LEVEL_INFO = Level.INFO; 42 /** 43 * The josm internal log level to print debug output 44 */ 45 public static final Level LEVEL_DEBUG = Level.FINE; 46 /** 47 * The finest log level josm supports. This lets josm print a lot of debug output. 48 */ 49 public static final Level LEVEL_TRACE = Level.FINEST; 50 private static final Logger LOGGER = Logger.getAnonymousLogger(); 51 private static final RememberWarningHandler WARNINGS = new RememberWarningHandler(); 52 53 static { 54 LOGGER.setLevel(Level.ALL); 55 LOGGER.setUseParentHandlers(false); 56 57 ConsoleHandler stderr = new ConsoleHandler(); 58 LOGGER.addHandler(stderr); 59 stderr.setLevel(LEVEL_WARN); 60 61 ConsoleHandler stdout = new ConsoleHandler() { 62 @Override 63 protected synchronized void setOutputStream(OutputStream out) { 64 // overwrite output stream. 65 super.setOutputStream(System.out); 66 } 67 68 @Override 69 public void publish(LogRecord record) { 70 if (!stderr.isLoggable(record)) { 71 super.publish(record); 72 } 73 } 74 }; 75 LOGGER.addHandler(stdout); 76 stdout.setLevel(Level.ALL); 77 78 LOGGER.addHandler(WARNINGS); 79 } 80 81 private Logging() { 82 // hide 83 } 84 85 /** 86 * Set the global log level. 87 * @param level The log level to use 88 */ 89 public static void setLogLevel(Level level) { 90 LOGGER.setLevel(level); 91 } 92 93 /** 94 * Prints an error message if logging is on. 95 * @param message The message to print. 96 */ 97 public static void error(String message) { 98 logPrivate(LEVEL_ERROR, message); 99 } 100 101 /** 102 * Prints a formatted error message if logging is on. Calls {@link MessageFormat#format} 103 * function to format text. 104 * @param pattern The formatted message to print. 105 * @param args The objects to insert into format string. 106 */ 107 public static void error(String pattern, Object... args) { 108 logPrivate(LEVEL_ERROR, pattern, args); 109 } 110 111 /** 112 * Prints a warning message if logging is on. 113 * @param message The message to print. 114 */ 115 public static void warn(String message) { 116 logPrivate(LEVEL_WARN, message); 117 } 118 119 /** 120 * Prints a formatted warning message if logging is on. Calls {@link MessageFormat#format} 121 * function to format text. 122 * @param pattern The formatted message to print. 123 * @param args The objects to insert into format string. 124 */ 125 public static void warn(String pattern, Object... args) { 126 logPrivate(LEVEL_WARN, pattern, args); 127 } 128 129 /** 130 * Prints a info message if logging is on. 131 * @param message The message to print. 132 */ 133 public static void info(String message) { 134 logPrivate(LEVEL_INFO, message); 135 } 136 137 /** 138 * Prints a formatted info message if logging is on. Calls {@link MessageFormat#format} 139 * function to format text. 140 * @param pattern The formatted message to print. 141 * @param args The objects to insert into format string. 142 */ 143 public static void info(String pattern, Object... args) { 144 logPrivate(LEVEL_INFO, pattern, args); 145 } 146 147 /** 148 * Prints a debug message if logging is on. 149 * @param message The message to print. 150 */ 151 public static void debug(String message) { 152 logPrivate(LEVEL_DEBUG, message); 153 } 154 155 /** 156 * Prints a formatted debug message if logging is on. Calls {@link MessageFormat#format} 157 * function to format text. 158 * @param pattern The formatted message to print. 159 * @param args The objects to insert into format string. 160 */ 161 public static void debug(String pattern, Object... args) { 162 logPrivate(LEVEL_DEBUG, pattern, args); 163 } 164 165 /** 166 * Prints a trace message if logging is on. 167 * @param message The message to print. 168 */ 169 public static void trace(String message) { 170 logPrivate(LEVEL_TRACE, message); 171 } 172 173 /** 174 * Prints a formatted trace message if logging is on. Calls {@link MessageFormat#format} 175 * function to format text. 176 * @param pattern The formatted message to print. 177 * @param args The objects to insert into format string. 178 */ 179 public static void trace(String pattern, Object... args) { 180 logPrivate(LEVEL_TRACE, pattern, args); 181 } 182 183 /** 184 * Logs a throwable that happened. 185 * @param level The level. 186 * @param t The throwable that should be logged. 187 */ 188 public static void log(Level level, Throwable t) { 189 logPrivate(level, () -> getErrorLog(null, t)); 190 } 191 192 /** 193 * Logs a throwable that happened. 194 * @param level The level. 195 * @param message An additional error message 196 * @param t The throwable that caused the message 197 */ 198 public static void log(Level level, String message, Throwable t) { 199 logPrivate(level, () -> getErrorLog(message, t)); 200 } 201 202 /** 203 * Logs a throwable that happened. Adds the stack trace to the log. 204 * @param level The level. 205 * @param t The throwable that should be logged. 206 */ 207 public static void logWithStackTrace(Level level, Throwable t) { 208 logPrivate(level, () -> getErrorLogWithStack(null, t)); 209 } 210 211 /** 212 * Logs a throwable that happened. Adds the stack trace to the log. 213 * @param level The level. 214 * @param message An additional error message 215 * @param t The throwable that should be logged. 216 */ 217 public static void logWithStackTrace(Level level, String message, Throwable t) { 218 logPrivate(level, () -> getErrorLogWithStack(message, t)); 219 } 220 221 private static void logPrivate(Level level, String pattern, Object... args) { 222 logPrivate(level, () -> MessageFormat.format(pattern, args)); 223 } 224 225 private static void logPrivate(Level level, String message) { 226 logPrivate(level, () -> message); 227 } 228 229 private static void logPrivate(Level level, Supplier<String> supplier) { 230 // all log methods immeadiately call one of the logPrivate methods. 231 if (LOGGER.isLoggable(level)) { 232 StackTraceElement callingMethod = BugReport.getCallingMethod(1, Logging.class.getName(), name -> !"logPrivate".equals(name)); 233 LOGGER.logp(level, callingMethod.getClassName(), callingMethod.getMethodName(), supplier); 234 } 235 } 236 237 /** 238 * Tests if a given log level is enabled. This can be used to avoid constructing debug data if required. 239 * 240 * For formatting text, you should use the {@link #debug(String, Object...)} message 241 * @param level A lvele constant. You can e.g. use {@link Logging#LEVEL_ERROR} 242 * @return <code>true</code> if debug is enabled. 243 */ 244 public static boolean isLoggingEnabled(Level level) { 245 return LOGGER.isLoggable(level); 246 } 247 248 private static String getErrorLog(String message, Throwable t) { 249 StringBuilder sb = new StringBuilder(); 250 if (message != null) { 251 sb.append(message).append(": "); 252 } 253 sb.append(getErrorMessage(t)); 254 return sb.toString(); 255 } 256 257 private static String getErrorLogWithStack(String message, Throwable t) { 258 StringWriter sb = new StringWriter(); 259 sb.append(getErrorLog(message, t)); 260 sb.append('\n'); 261 t.printStackTrace(new PrintWriter(sb)); 262 return sb.toString(); 263 } 264 265 /** 266 * Returns a human-readable message of error, also usable for developers. 267 * @param t The error 268 * @return The human-readable error message 269 */ 270 public static String getErrorMessage(Throwable t) { 271 if (t == null) { 272 return "(no error)"; 273 } 274 StringBuilder sb = new StringBuilder(t.getClass().getName()); 275 String msg = t.getMessage(); 276 if (msg != null) { 277 sb.append(": ").append(msg.trim()); 278 } 279 Throwable cause = t.getCause(); 280 if (cause != null && !cause.equals(t)) { 281 sb.append(". ").append(tr("Cause: ")).append(getErrorMessage(cause)); 282 } 283 return sb.toString(); 284 } 285 286 /** 287 * Clear the list of last warnings 288 */ 289 public static void clearLastErrorAndWarnings() { 290 WARNINGS.clear(); 291 } 292 293 /** 294 * Get the last error and warning messages in the order in which they were received. 295 * @return The last errors and warnings. 296 */ 297 public static List<String> getLastErrorAndWarnings() { 298 return WARNINGS.getMessages(); 299 } 300 301 /** 302 * Provides direct access to the logger used. Use of methods like {@link #warn(String)} is prefered. 303 * @return The logger 304 */ 305 public static Logger getLogger() { 306 return LOGGER; 307 } 308 309 private static class RememberWarningHandler extends Handler { 310 private final String[] log = new String[10]; 311 private int messagesLogged; 312 313 RememberWarningHandler() { 314 setLevel(LEVEL_WARN); 315 } 316 317 synchronized void clear() { 318 messagesLogged = 0; 319 Arrays.fill(log, null); 320 } 321 322 @Override 323 public synchronized void publish(LogRecord record) { 324 if (!isLoggable(record)) { 325 return; 326 } 327 328 String msg = getPrefix(record) + record.getMessage(); 329 330 // Only remember first line of message 331 int idx = msg.indexOf('\n'); 332 if (idx > 0) { 333 msg = msg.substring(0, idx); 334 } 335 log[messagesLogged % log.length] = msg; 336 messagesLogged++; 337 } 338 339 private static String getPrefix(LogRecord record) { 340 if (record.getLevel().equals(LEVEL_WARN)) { 341 return "W: "; 342 } else { 343 // worse than warn 344 return "E: "; 345 } 346 } 347 348 synchronized List<String> getMessages() { 349 List<String> logged = Arrays.asList(log); 350 ArrayList<String> res = new ArrayList<>(); 351 int logOffset = messagesLogged % log.length; 352 if (messagesLogged > logOffset) { 353 res.addAll(logged.subList(logOffset, log.length)); 354 } 355 res.addAll(logged.subList(0, logOffset)); 356 return res; 357 } 358 359 @Override 360 public synchronized void flush() { 361 // nothing to do 362 } 363 364 @Override 365 public void close() { 366 // nothing to do 367 } 368 } 369 } -
src/org/openstreetmap/josm/tools/bugreport/BugReport.java
diff --git a/src/org/openstreetmap/josm/tools/bugreport/BugReport.java b/src/org/openstreetmap/josm/tools/bugreport/BugReport.java index d47586f..426cb59 100644
a b import java.io.PrintWriter; 5 5 import java.io.Serializable; 6 6 import java.io.StringWriter; 7 7 import java.util.concurrent.CopyOnWriteArrayList; 8 import java.util.function.Predicate; 8 9 9 10 import org.openstreetmap.josm.actions.ShowStatusReportAction; 10 11 … … public final class BugReport implements Serializable { 180 181 * @return The method name. 181 182 */ 182 183 public static String getCallingMethod(int offset) { 183 StackTraceElement[] stackTrace = Thread.currentThread().getStackTrace();184 184 String className = BugReport.class.getName(); 185 String methodName = "getCallingMethod"; 186 StackTraceElement found = getCallingMethod(offset, className, methodName::equals); 187 if (found != null) { 188 return found.getClassName().replaceFirst(".*\\.", "") + '#' + found.getMethodName(); 189 } else { 190 return "?"; 191 } 192 } 193 194 /** 195 * Find the method that called the given method on the current stack trace. 196 * @param offset 197 * How many methods to look back in the stack trace. 1 gives the method calling this method, 0 gives you getCallingMethod(). 198 * @param className The name of the class to search for 199 * @param methodName The name of the method to search for 200 * @return The class and method name or null if it is unknown. 201 */ 202 public static StackTraceElement getCallingMethod(int offset, String className, Predicate<String> methodName) { 203 StackTraceElement[] stackTrace = Thread.currentThread().getStackTrace(); 185 204 for (int i = 0; i < stackTrace.length - offset; i++) { 186 205 StackTraceElement element = stackTrace[i]; 187 if (className.equals(element.getClassName()) && "getCallingMethod".equals(element.getMethodName())) {206 if (className.equals(element.getClassName()) && methodName.test(element.getMethodName())) { 188 207 StackTraceElement toReturn = stackTrace[i + offset]; 189 return toReturn .getClassName().replaceFirst(".*\\.", "") + '#' + toReturn.getMethodName();208 return toReturn; 190 209 } 191 210 } 192 return "?";211 return null; 193 212 } 194 213 195 214 /** -
test/unit/org/openstreetmap/josm/JOSMFixture.java
diff --git a/test/unit/org/openstreetmap/josm/JOSMFixture.java b/test/unit/org/openstreetmap/josm/JOSMFixture.java index 5e31aa7..7596606 100644
a b import org.openstreetmap.josm.gui.util.GuiHelper; 21 21 import org.openstreetmap.josm.io.CertificateAmendment; 22 22 import org.openstreetmap.josm.io.OsmApi; 23 23 import org.openstreetmap.josm.tools.I18n; 24 import org.openstreetmap.josm.tools.Logging; 24 25 25 26 /** 26 27 * Fixture to define a proper and safe environment before running tests. … … public class JOSMFixture { 99 100 Main.platform.preStartupHook(); 100 101 101 102 Main.logLevel = 3; 103 Logging.setLogLevel(Logging.LEVEL_INFO); 102 104 Main.pref.init(false); 103 105 Main.pref.put("osm-server.url", "http://api06.dev.openstreetmap.org/api"); 104 106 I18n.set(Main.pref.get("language", "en")); -
test/unit/org/openstreetmap/josm/testutils/JOSMTestRules.java
diff --git a/test/unit/org/openstreetmap/josm/testutils/JOSMTestRules.java b/test/unit/org/openstreetmap/josm/testutils/JOSMTestRules.java index 634b625..d46b251 100644
a b import java.io.File; 5 5 import java.io.IOException; 6 6 import java.text.MessageFormat; 7 7 import java.util.TimeZone; 8 import java.util.logging.Level; 8 9 9 10 import org.junit.rules.TemporaryFolder; 10 11 import org.junit.rules.TestRule; … … import org.openstreetmap.josm.io.OsmApi; 19 20 import org.openstreetmap.josm.io.OsmApiInitializationException; 20 21 import org.openstreetmap.josm.io.OsmTransferCanceledException; 21 22 import org.openstreetmap.josm.tools.I18n; 23 import org.openstreetmap.josm.tools.Logging; 22 24 import org.openstreetmap.josm.tools.MemoryManagerTest; 23 25 import org.openstreetmap.josm.tools.date.DateUtils; 24 26 … … public class JOSMTestRules implements TestRule { 182 184 TimeZone.setDefault(DateUtils.UTC); 183 185 // Set log level to info 184 186 Main.logLevel = 3; 187 Logging.setLogLevel(Level.INFO); 185 188 186 189 // Set up i18n 187 190 if (i18n != null) {