summaryrefslogtreecommitdiffstats
path: root/src/main/java/derms/replica2/ResponderServer.java
blob: 02ff6b6970c39eaab3420eeb97ecc7fc51e137e3 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
package derms.replica2;

import java.io.IOException;
import java.net.InetAddress;
import java.time.Duration;
import java.util.Collection;
import java.util.NoSuchElementException;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import java.util.logging.Logger;

class ResponderServer {
	static final Duration timeout = Duration.ofSeconds(5);

	private City city;
	private Resources resources;
	private Servers servers;
	private Logger log;

	ResponderServer(City city, Resources resources, Servers servers) throws IOException {
		this.city = city;
		this.resources = resources;
		this.servers = servers;
		this.log = DermsLogger.getLogger(this.getClass());
	}

	ResponderServer() throws IOException {
		this(new City(), new Resources(), new Servers());
	}

	void addResource(Resource r) {
		resources.add(r);
		log.info("Added resource "+r+" - success");
	}

	void removeResource(ResourceID rid, int duration) throws NoSuchResourceException {
		log.info("Remove duration "+duration+" from "+rid);
		try {
			Resource resource = resources.getByID(rid);
			synchronized (resource) {
				if (duration < 0 || duration >= resource.duration) {
					resources.removeByID(rid);
					log.info("Removed resource "+rid+" - success");
				} else {
					resource.duration -= duration;
					log.info("Removed duration from resource "+rid+". New duration: "+resource.duration+" - success");
				}
			}
		} catch (NoSuchElementException e) {
			// Wanted to remove duration from resource.
			if (duration >= 0) {
				String msg = "Cannot remove duration from "+rid+": resource does not exist.";
				log.warning(msg);
				throw new NoSuchResourceException(msg);
			}

			// Duration is negative---wanted to remove resource completely.
			// Success because it is already removed.
			log.info("Not removing "+rid+": resource does not exist.");
		}
	}

	Resource[] listResourceAvailability(ResourceType rname) throws ServerCommunicationError {
		log.info("Request for available "+rname);
		Collection<Resource> availableResources = ConcurrentHashMap.newKeySet();
		ExecutorService pool = Executors.newFixedThreadPool(servers.size());
		try {
			for (InetAddress serverAddr : servers.all()) {
				pool.execute(new ResourceAvailability.Client(serverAddr, rname, availableResources));
			}
		} catch (IOException e) {
			String msg = "Failed to start ResourceAvailability Client: "+e.getMessage();
			log.severe(msg);
			throw new ServerCommunicationError("ResourceAvailability: "+msg);
		}

		log.fine("Started worker threads");
		pool.shutdown();
		boolean terminated;
		try {
			terminated = pool.awaitTermination(timeout.toMillis(), TimeUnit.MILLISECONDS);
		} catch (InterruptedException e) {
			throw new ServerCommunicationError("listResourceAvailability(): listResourceAvailability() interrupted: "+e.getMessage());
		}
		if (!terminated) {
			throw new ServerCommunicationError("ResourceAvailability: request timed out: no response after "+timeout.toString());
		}
		log.info("Response length "+availableResources.size());
		Resource[] arr = new Resource[0];
		return availableResources.toArray(arr);
	}
}