package aQute.bnd.build;

import java.io.File;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import aQute.bnd.service.RepositoryPlugin;
import aQute.service.reporter.Reporter;

/**
 * This class is intended to be used by the users of a {@link RepositoryPlugin}.
 * The
 * {@link RepositoryPlugin#get(String, aQute.bnd.version.Version, java.util.Map, aQute.bnd.service.RepositoryPlugin.DownloadListener...)}
 * method takes one or more Download Listeners. These are called back with the
 * success or failure of a download. This class is a simple implementation of
 * this model, just call {@link #getReason()} and it blocks until success or
 * failure is called.
 */
public class DownloadBlocker implements RepositoryPlugin.DownloadListener {
	private final static Logger logger = LoggerFactory.getLogger(DownloadBlocker.class);

	public enum Stage {
		INIT, SUCCESS, FAILURE
	};

	private volatile Stage	stage	= Stage.INIT;
	private volatile String	failure;
	private volatile File	file;
	private final Reporter	reporter;

	public DownloadBlocker(Reporter reporter) {
		this.reporter = reporter;
	}

	/*
	 * (non-Javadoc)
	 * @see
	 * aQute.bnd.service.RepositoryPlugin.DownloadListener#success(java.io.File)
	 */
	public void success(File file) throws Exception {
		synchronized (this) {
			assert stage == Stage.INIT;
			stage = Stage.SUCCESS;
			this.file = file;
			notifyAll();
		}
		logger.debug("successfully downloaded {}", file);
	}

	/*
	 * (non-Javadoc)
	 * @see
	 * aQute.bnd.service.RepositoryPlugin.DownloadListener#failure(java.io.File,
	 * java.lang.String)
	 */
	public void failure(File file, String reason) throws Exception {
		synchronized (this) {
			assert stage == Stage.INIT;
			stage = Stage.FAILURE;
			this.failure = reason;
			this.file = file;
			notifyAll();
		}
		if (reporter != null)
			reporter.error("Download %s %s", reason, file);
	}

	/*
	 * (non-Javadoc)
	 * @see
	 * aQute.bnd.service.RepositoryPlugin.DownloadListener#progress(java.io.
	 * File, int)
	 */
	public boolean progress(File file, int percentage) throws Exception {
		assert stage == Stage.INIT;
		return true;
	}

	/**
	 * Return a failure reason or null. This method will block until either
	 * {@link #success(File)} or {@link #failure(File, String)} has been called.
	 * It can be called many times.
	 * 
	 * @return null or a reason for a failure
	 */
	public synchronized String getReason() {
		try {
			while (stage == Stage.INIT)
				wait();
		} catch (InterruptedException e) {
			return "Interrupted";
		}

		return failure;
	}

	/**
	 * Return the stage we're in
	 * 
	 * @return the current stage
	 */
	public Stage getStage() {
		return stage;
	}

	public File getFile() {
		getReason();
		return file;
	}

	@Override
	public String toString() {
		return "DownloadBlocker [stage=" + stage + ", failure=" + failure + ", file=" + file + "]";
	}
}

@@ -39,16 +39,60 @@
 io.File;
+%0Aimport java.util.concurrent.CountDownLatch;
 %0A%0Aimport
@@ -988,24 +988,19 @@
 ate 
-volatile 
 String%09
+%09%09%09%09
 fail
@@ -1017,21 +1017,16 @@
 ate 
-volatile 
 File
+%09%09%09%09
 %09fil
@@ -1061,16 +1061,56 @@
 eporter;
+%0A%09private final CountDownLatch%09resolved;
 %0A%0A%09publi
@@ -1176,16 +1176,52 @@
 porter;%0A
+%09%09resolved = new CountDownLatch(1);%0A
 %09%7D%0A%0A%09/*%0A
@@ -1389,39 +1389,140 @@
 %09%09synchronized (
-this) %7B
+resolved) %7B%0A%09%09%09if (resolved.getCount() == 0) %7B%0A%09%09%09%09throw new IllegalStateException(%22already resolved%22);%0A%09%09%09%7D
 %0A%09%09%09assert stage
@@ -1583,33 +1583,42 @@
  = file;%0A%09%09%09
-notifyAll
+resolved.countDown
 ();%0A%09%09%7D%0A%09%09lo
@@ -1891,15 +1891,116 @@
 ed (
-this) %7B
+resolved) %7B%0A%09%09%09if (resolved.getCount() == 0) %7B%0A%09%09%09%09throw new IllegalStateException(%22already resolved%22);%0A%09%09%09%7D
 %0A%09%09%09
@@ -2107,17 +2107,26 @@
 %0A%09%09%09
-notifyAll
+resolved.countDown
 ();%0A
@@ -2703,29 +2703,16 @@
 %09public 
-synchronized 
 String g
@@ -2739,46 +2739,43 @@
 %0A%09%09%09
-while (stage == Stage.INIT)%0A%09%09%09%09wait()
+resolved.await();%0A%09%09%09return failure
 ;%0A%09%09
@@ -2841,27 +2841,8 @@
 %0A%09%09%7D
-%0A%0A%09%09return failure;
 %0A%09%7D%0A
@@ -2995,21 +2995,36 @@
 %7B%0A%09%09
-getReason
+try %7B%0A%09%09%09resolved.await
 ();%0A
+%09
 %09%09re
@@ -3034,16 +3034,73 @@
 n file;%0A
+%09%09%7D catch (InterruptedException e) %7B%0A%09%09%09return null;%0A%09%09%7D%0A
 %09%7D%0A%0A%09@Ov

Tidy up blocking logic by using CountDownLatch