/src/Client.java

https://bitbucket.org/cairomax/labreti-broker · Java · 239 lines · 103 code · 29 blank · 107 comment · 1 complexity · e5869a3de1c420a5b13902cc2ce637a1 MD5 · raw file

  1. import java.lang.Thread.UncaughtExceptionHandler;
  2. import java.net.InetAddress;
  3. import java.net.UnknownHostException;
  4. import java.rmi.Naming;
  5. import java.rmi.RemoteException;
  6. import java.util.concurrent.atomic.AtomicInteger;
  7. /**
  8. * Classe eseguibile che lancia un client che mette a disposizione e richiede
  9. * risorse a un pool.
  10. *
  11. * @see #start()
  12. */
  13. public class Client {
  14. /** Numero totali di risorse presenti su un client */
  15. private static final int MAX_RESOURCES = 100;
  16. /** Porta su cui il broker è in ascolto con Java RMI */
  17. private static final int BROKER_PORT = 1111;
  18. /** Il broker remoto che gestisce l'allocazione di risorse */
  19. private final Broker broker;
  20. /**
  21. * Numero di risorse attualmente disponibili su questo client.
  22. * <p>
  23. * Si usa {@link AtomicInteger} per supportare incrementi e decrementi
  24. * atomici, senza ricorrere ai lock.
  25. */
  26. private final AtomicInteger availableResources = new AtomicInteger();
  27. /**
  28. * Identificativo di questo client.
  29. * <p>
  30. * Contiene l'indirizzo IP dell'host su cui gira il client.
  31. */
  32. private final String user;
  33. /**
  34. * Costruttore di default.
  35. *
  36. * @param broker
  37. * il broker che implementa il pool di risorse
  38. */
  39. public Client(Broker broker) {
  40. this.broker = broker;
  41. try {
  42. user = InetAddress.getLocalHost().getHostAddress();
  43. } catch (UnknownHostException e) {
  44. throw new RuntimeException(e);
  45. }
  46. }
  47. /**
  48. * Avvia il client.
  49. * <p>
  50. * Questo metodo inizializza i thread necessari al funzionamento del client.
  51. * In particolare:
  52. * <ul>
  53. * <li>un thread che ascolta le richieste di riservare risorse (
  54. * {@link ReserveProcessorThread})
  55. * <li>un thread che simula la liberazioni di risorse precedentemente
  56. * allocate ({@link ResourceFreeingSimulatorThread})
  57. * <li>un thread che simula le richieste di nuove risorse (
  58. * {@link ResourceTakingSimulatorThread})
  59. * </ul>
  60. * <p>
  61. * Prima di avviare la simulazione, questo metodo notifica il broker che
  62. * tutte le risorse su questo client sono disponibili, tramite una chiamata
  63. * a {@link #give(int)}.
  64. */
  65. public void start() {
  66. System.err.println(String.format("Client %s: starting", user));
  67. Thread.setDefaultUncaughtExceptionHandler(new UncaughtExceptionHandler() {
  68. @Override
  69. public void uncaughtException(Thread t, Throwable e) {
  70. e.printStackTrace();
  71. System.exit(0);
  72. }
  73. });
  74. final ReserveProcessorThread reserveProcessorThread = new ReserveProcessorThread(
  75. this);
  76. final ResourceFreeingSimulatorThread resourceFreeingSimulator = new ResourceFreeingSimulatorThread(
  77. this);
  78. final ResourceTakingSimulatorThread resourceTakingSimulatorThread = new ResourceTakingSimulatorThread(
  79. this);
  80. reserveProcessorThread.start();
  81. give(getTotalResources());
  82. resourceFreeingSimulator.start();
  83. resourceTakingSimulatorThread.start();
  84. }
  85. /**
  86. * Riserva un dato numero di risorse, in seguito a una richiesta ricevuta
  87. * dal server.
  88. * <p>
  89. * L'operazione è implementata decrementando atomicamente
  90. * {@link #availableResources}.
  91. *
  92. * @param resourcesToReserve
  93. * il numero di risorse da riservare
  94. * @throws InsufficientResourcesException
  95. * se vengono riservate più risorse di quelle disponibili
  96. */
  97. public void reserve(final int resourcesToReserve)
  98. throws InsufficientResourcesException {
  99. final int remainingResources = availableResources
  100. .addAndGet(-resourcesToReserve);
  101. System.err.println(String.format("Client %s: reserving %d resources",
  102. user, resourcesToReserve));
  103. System.out.println(String.format("Client %s: now I have %d resources",
  104. user, remainingResources));
  105. if (remainingResources < 0) {
  106. availableResources.addAndGet(resourcesToReserve);
  107. throw new InsufficientResourcesException();
  108. }
  109. }
  110. /**
  111. * Notifica il server della liberazione di un dato numero di risorse.
  112. * <p>
  113. * L'operazione è implementata incrementando atomicamente
  114. * {@link #availableResources} e invocando {@link Broker#give(String, int)}
  115. * con l'identificativo di questo client come primo argomento.
  116. *
  117. * @param resourcesToGive
  118. * il numero di risorse liberate
  119. */
  120. public void give(int resourcesToGive) {
  121. try {
  122. System.err.println(String
  123. .format("Client %s: giving %d resources... ", user,
  124. resourcesToGive));
  125. availableResources.addAndGet(resourcesToGive);
  126. broker.give(user, resourcesToGive);
  127. System.err.println(String.format(
  128. "Client %s: giving %d resources... done!", user,
  129. resourcesToGive));
  130. System.out.println(String.format(
  131. "Client %s: now I have %d resources", user,
  132. availableResources.get()));
  133. } catch (RemoteException e) {
  134. throw new RuntimeException(e);
  135. }
  136. }
  137. /**
  138. * Richiede al server di allocare un dato numero di risorse.
  139. * <p>
  140. * L'operazione viene effettuata decrementando atomicamente
  141. * {@link #availableResources} e invocando {@link Broker#take(String, int)}
  142. * con l'identificativo di questo client come primo argomento.
  143. *
  144. * @param resources
  145. * il numero di risorse da allocare
  146. */
  147. public void take(int resources) {
  148. System.err.println(String.format("Client %s: taking %d resources... ",
  149. user, resources));
  150. try {
  151. final boolean wereTaken = broker.take(user, resources);
  152. System.err.println(String.format(
  153. "Client %s: taking %d resources... %s", user, resources,
  154. wereTaken ? "taken!" : "NOT available!"));
  155. } catch (RemoteException e) {
  156. throw new RuntimeException(e);
  157. }
  158. }
  159. /**
  160. * Restituisce il numero totale di risorse (disponibili o allocate) su
  161. * questo client.
  162. * <p>
  163. * Restituisce sempre il valore di {@link #MAX_RESOURCES}.
  164. *
  165. * @return il numero totale di risorse su questo client.
  166. */
  167. public int getTotalResources() {
  168. return MAX_RESOURCES;
  169. }
  170. /**
  171. * Restituisce il numero di risorse disponibili (non allocate) su questo
  172. * client.
  173. * <p>
  174. * Restituisce il valore attuale di {@link #availableResources}.
  175. *
  176. * @return il numero di risorse disponibili su questo client.
  177. */
  178. public int getAvailableResources() {
  179. return availableResources.get();
  180. }
  181. /**
  182. * Metodo principale del client.
  183. * <p>
  184. * Esegue le seguenti operationi:
  185. * <ol>
  186. * <li>ottiene un'implementazione remota di {@link Broker}, tramite una
  187. * chiamata a {@link Naming#lookup(String)}
  188. * <li>costruisce un'istanza di {@link Client}, passando al costruttore il
  189. * broker appena inizializzato
  190. * <li>invoca {@link Client#start()}
  191. * </ol>
  192. *
  193. * @param args
  194. * argomenti da linea di comando, ignorati
  195. */
  196. public static void main(String[] args) {
  197. String server = args[0];
  198. final String url = "rmi://" + server + ":" + BROKER_PORT
  199. + "/ResourceBroker";
  200. System.err.println("Client: looking up broker at URL: " + url);
  201. Broker broker;
  202. try {
  203. broker = (Broker) Naming.lookup(url);
  204. } catch (Exception e) {
  205. throw new RuntimeException(e);
  206. }
  207. Client client = new Client(broker);
  208. client.start();
  209. }
  210. }