remove requests from table when node disconnects
[jSite2.git] / src / net / pterodactylus / jsite / core / RequestManager.java
1 /*
2  * jSite2 - RequestManager.java -
3  * Copyright © 2008 David Roden
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation; either version 2 of the License, or
8  * (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Software
17  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18  */
19
20 package net.pterodactylus.jsite.core;
21
22 import java.io.IOException;
23 import java.util.ArrayList;
24 import java.util.Collections;
25 import java.util.HashMap;
26 import java.util.List;
27 import java.util.Map;
28 import java.util.logging.Level;
29 import java.util.logging.Logger;
30
31 import net.pterodactylus.fcp.highlevel.HighLevelCallback;
32 import net.pterodactylus.fcp.highlevel.HighLevelCallbackListener;
33 import net.pterodactylus.fcp.highlevel.HighLevelClient;
34 import net.pterodactylus.fcp.highlevel.HighLevelProgress;
35 import net.pterodactylus.fcp.highlevel.HighLevelProgressListener;
36 import net.pterodactylus.fcp.highlevel.RequestListResult;
37 import net.pterodactylus.fcp.highlevel.RequestResult;
38 import net.pterodactylus.util.logging.Logging;
39
40 /**
41  * The request manager keeps track of all the request on all connected nodes.
42  * The request manager is added to the {@link NodeManager} as a
43  * {@link NodeListener} so that it can fire request-removed events in case a
44  * node is disconnected.
45  * 
46  * @author David ‘Bombe’ Roden <bombe@freenetproject.org>
47  * @version $Id$
48  */
49 public class RequestManager implements NodeListener, HighLevelProgressListener {
50
51         /** Logger. */
52         private static final Logger logger = Logging.getLogger(RequestManager.class.getName());
53
54         /** Request listeners. */
55         private List<RequestListener> requestListeners = Collections.synchronizedList(new ArrayList<RequestListener>());
56
57         /** The node manager. */
58         private NodeManager nodeManager;
59
60         /** Request lists for all nodes. */
61         @SuppressWarnings("unused")
62         private Map<Node, Map<String, Request>> nodeRequests = Collections.synchronizedMap(new HashMap<Node, Map<String, Request>>());
63
64         //
65         // EVENT MANAGEMENT
66         //
67
68         /**
69          * Adds a request listener.
70          * 
71          * @param requestListener
72          *            The request listener to add
73          */
74         public void addRequestListener(RequestListener requestListener) {
75                 requestListeners.add(requestListener);
76         }
77
78         /**
79          * Removes a request listener.
80          * 
81          * @param requestListener
82          *            The request listener to remove
83          */
84         public void removeRequestListener(RequestListener requestListener) {
85                 requestListeners.remove(requestListener);
86         }
87
88         /**
89          * Notifies all listeners that a request was added.
90          * 
91          * @param request
92          *            The request that was added
93          */
94         private void fireRequestAdded(Request request) {
95                 for (RequestListener requestListener: requestListeners) {
96                         requestListener.requestAdded(request);
97                 }
98         }
99
100         /**
101          * Notifies all listeners that a request progressed.
102          * 
103          * @param request
104          *            The request
105          */
106         private void fireRequestProgressed(Request request) {
107                 for (RequestListener requestListener: requestListeners) {
108                         requestListener.requestProgressed(request);
109                 }
110         }
111
112         /**
113          * Notifies all listeners that a request was removed.
114          * 
115          * @param request
116          *            The request that was removed
117          */
118         private void fireRequestRemoved(Request request) {
119                 for (RequestListener requestListener: requestListeners) {
120                         requestListener.requestRemoved(request);
121                 }
122         }
123
124         //
125         // ACCESSORS
126         //
127
128         /**
129          * Sets the node manager to use.
130          * 
131          * @param nodeManager
132          *            The node manager
133          */
134         public void setNodeManager(NodeManager nodeManager) {
135                 this.nodeManager = nodeManager;
136         }
137
138         //
139         // ACTIONS
140         //
141
142         //
143         // PRIVATE ACTIONS
144         //
145
146         /**
147          * Requests a list of all running requests from a node. This method will
148          * block until the request has been sent!
149          * 
150          * @param node
151          *            The node to get all requests for
152          * @throws IOException
153          *             if an I/O error occurs while communicating with the node
154          */
155         private void getRequests(final Node node) throws IOException {
156                 HighLevelClient highLevelClient = nodeManager.getHighLevelClient(node);
157                 if (highLevelClient == null) {
158                         logger.log(Level.WARNING, "no client for node: " + node);
159                         return;
160                 }
161                 final Map<String, Request> identifierRequests = new HashMap<String, Request>();
162                 nodeRequests.put(node, identifierRequests);
163                 HighLevelCallback<RequestListResult> requestListCallback = highLevelClient.getRequests();
164                 requestListCallback.addHighLevelCallbackListener(new HighLevelCallbackListener<RequestListResult>() {
165
166                         @SuppressWarnings("synthetic-access")
167                         public void gotResult(HighLevelCallback<RequestListResult> highLevelCallback) {
168                                 RequestListResult requestListResult;
169                                 try {
170                                         requestListResult = highLevelCallback.getResult();
171                                 } catch (InterruptedException e) {
172                                         logger.log(Level.SEVERE, "getResult() blocked and was interrupted");
173                                         return;
174                                 }
175                                 for (RequestResult requestResult: requestListResult) {
176                                         Request request = new Request(node, requestResult.getIdentifier());
177                                         identifierRequests.put(requestResult.getIdentifier(), request);
178                                         /* TODO - fill request */
179                                         fireRequestAdded(request);
180                                 }
181                         }
182                 });
183         }
184
185         //
186         // INTERFACE NodeListener
187         //
188
189         /**
190          * {@inheritDoc}
191          */
192         public void nodeAdded(Node node) {
193                 HighLevelClient highLevelClient = nodeManager.getHighLevelClient(node);
194                 if (highLevelClient == null) {
195                         logger.warning("got nodeAdded but no high-level client: " + node);
196                         return;
197                 }
198                 highLevelClient.addHighLevelProgressListener(this);
199         }
200
201         /**
202          * {@inheritDoc}
203          */
204         public void nodeRemoved(Node node) {
205                 HighLevelClient highLevelClient = nodeManager.getHighLevelClient(node);
206                 if (highLevelClient == null) {
207                         logger.warning("got nodeRemoved but no high-level client: " + node);
208                         return;
209                 }
210                 highLevelClient.removeHighLevelProgressListener(this);
211         }
212
213         /**
214          * {@inheritDoc}
215          */
216         public void nodeConnected(Node node) {
217                 HighLevelClient highLevelClient = nodeManager.getHighLevelClient(node);
218                 if (highLevelClient == null) {
219                         logger.log(Level.WARNING, "got no high-level client for node " + node);
220                         return;
221                 }
222                 try {
223                         highLevelClient.setWatchGlobal(true);
224                         getRequests(node);
225                 } catch (IOException e) {
226                         /* ignore exception, disconnects are handled elsewhere. */
227                 }
228         }
229
230         /**
231          * {@inheritDoc}
232          */
233         public void nodeConnectionFailed(Node node, Throwable cause) {
234                 /* we don't care about this. */
235         }
236
237         /**
238          * {@inheritDoc}
239          */
240         public void nodeDisconnected(Node node, Throwable throwable) {
241                 Map<String, Request> identifierRequests = nodeRequests.get(node);
242                 if (identifierRequests == null) {
243                         logger.warning("got node without request map: " + node);
244                         return;
245                 }
246                 for (Request request: identifierRequests.values()) {
247                         fireRequestRemoved(request);
248                 }
249                 identifierRequests.clear();
250         }
251
252         //
253         // INTERFACE HighLevelProgressListener
254         //
255
256         /**
257          * @see net.pterodactylus.fcp.highlevel.HighLevelProgressListener#progressReceived(HighLevelClient,
258          *      String, HighLevelProgress)
259          */
260         public void progressReceived(HighLevelClient highLevelClient, String identifier, HighLevelProgress highLevelProgress) {
261                 Node node = nodeManager.getNode(highLevelClient);
262                 if (node == null) {
263                         logger.warning("got high-level client without node: " + highLevelClient);
264                         return;
265                 }
266                 Map<String, Request> identifierRequests = nodeRequests.get(node);
267                 if (identifierRequests == null) {
268                         logger.warning("got node without request map: " + node);
269                         return;
270                 }
271                 Request request = identifierRequests.get(identifier);
272                 if (request == null) {
273                         logger.warning("got progress for unknown request: " + identifier);
274                         return;
275                 }
276                 request.setTotalBlocks(highLevelProgress.getTotalBlocks());
277                 request.setRequiredBlocks(highLevelProgress.getRequiredBlocks());
278                 request.setSuccessfulBlocks(highLevelProgress.getSuccessfulBlocks());
279                 request.setFailedBlocks(highLevelProgress.getFailedBlocks());
280                 request.setFatallyFailedBlocks(highLevelProgress.getFatallyFailedBlocks());
281                 request.setTotalFinalized(highLevelProgress.isTotalFinalized());
282                 fireRequestProgressed(request);
283         }
284
285 }