@Override
	public void run() {
		try {
			doLockedAction(listenerLockPath, true, () -> {
				try (WatchService watchService = FileSystems.getDefault().newWatchService()) {
					urlFilesPath.register(watchService, StandardWatchEventKinds.ENTRY_CREATE);
					Msg.info(this, "Listening for GhidraGo Requests.");
					doLockedAction(listenerReadyLockPath, true, () -> {
						try {
							WatchKey key;
							while ((key = watchService.take()) != null) {
								for (WatchEvent<?> event : key.pollEvents()) {
									// only process events that are not null. null events could happen 
									// when event.kind() is OVERFLOW.
									if (event.context() != null) {
										Msg.trace(this, event.context() + " is a new file!");
										// get the url from the new url
										Path urlFilePath =
											urlFilesPath.resolve(event.context().toString());
										URL url = getGhidraURL(urlFilePath);
										urlFilePath.toFile().delete();
										if (url != null) {
											onNewUrl.accept(url);
										}
									}
								}
								key.reset();
							}
						}
						catch (InterruptedException e) {
							// watch service interrupted
						}
						return true;
					});
				}
				catch (FileLockInterruptionException | InterruptedIOException e) {
					return false;
				}
				catch (IOException | UnableToGetLockException e) {
					Swing.runNow(() -> Msg.showError(this, null,
						"GhidraGo Unable to Watch for New GhidraURL's", e));
					return false;
				}
				catch (ClosedWatchServiceException e) {
					// do nothing
				}
				finally {
					Msg.info(this, "No longer listening for GhidraGo Requests.");
				}
				return true;
			});
		}
		catch (OverlappingFileLockException | UnableToGetLockException e) {
			Swing.runNow(
				() -> Msg.showError(this, null, "GhidraGo Unable to Watch for New GhidraURL's", e));
		}
	}
Begin listening for urls in a non-blocking thread. If a listener already exists, the thread 
will wait until no listener exists and attempt to get the lock. Once the lock has been acquired
the listener will start watching for new urls and create a ready lock. Upon a new url being found,
the onNewUrl Consumer will be executed.
@param onNewUrl consumer method to execute upon finding a new url
@throws IOException if the Runnable cannot be created
Ghidra/Features/GhidraGo/src/main/java/ghidra/app/plugin/core/go/ipc/GhidraGoListener.java