skip known identifiers in initial request list
[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                                         String identifier = requestResult.getIdentifier();
177                                         if (identifierRequests.containsKey(identifier)) {
178                                                 continue;
179                                         }
180                                         Request request = new Request(node, identifier);
181                                         identifierRequests.put(requestResult.getIdentifier(), request);
182                                         /* TODO - fill request */
183                                         fireRequestAdded(request);
184                                 }
185                         }
186                 });
187         }
188
189         //
190         // INTERFACE NodeListener
191         //
192
193         /**
194          * {@inheritDoc}
195          */
196         public void nodeAdded(Node node) {
197                 HighLevelClient highLevelClient = nodeManager.getHighLevelClient(node);
198                 if (highLevelClient == null) {
199                         logger.warning("got nodeAdded but no high-level client: " + node);
200                         return;
201                 }
202                 highLevelClient.addHighLevelProgressListener(this);
203         }
204
205         /**
206          * {@inheritDoc}
207          */
208         public void nodeRemoved(Node node) {
209                 HighLevelClient highLevelClient = nodeManager.getHighLevelClient(node);
210                 if (highLevelClient == null) {
211                         logger.warning("got nodeRemoved but no high-level client: " + node);
212                         return;
213                 }
214                 highLevelClient.removeHighLevelProgressListener(this);
215         }
216
217         /**
218          * {@inheritDoc}
219          */
220         public void nodeConnected(Node node) {
221                 HighLevelClient highLevelClient = nodeManager.getHighLevelClient(node);
222                 if (highLevelClient == null) {
223                         logger.log(Level.WARNING, "got no high-level client for node " + node);
224                         return;
225                 }
226                 try {
227                         highLevelClient.setWatchGlobal(true);
228                         getRequests(node);
229                 } catch (IOException e) {
230                         /* ignore exception, disconnects are handled elsewhere. */
231                 }
232         }
233
234         /**
235          * {@inheritDoc}
236          */
237         public void nodeConnectionFailed(Node node, Throwable cause) {
238                 /* we don't care about this. */
239         }
240
241         /**
242          * {@inheritDoc}
243          */
244         public void nodeDisconnected(Node node, Throwable throwable) {
245                 Map<String, Request> identifierRequests = nodeRequests.get(node);
246                 if (identifierRequests == null) {
247                         logger.warning("got node without request map: " + node);
248                         return;
249                 }
250                 for (Request request: identifierRequests.values()) {
251                         fireRequestRemoved(request);
252                 }
253                 identifierRequests.clear();
254         }
255
256         //
257         // INTERFACE HighLevelProgressListener
258         //
259
260         /**
261          * @see net.pterodactylus.fcp.highlevel.HighLevelProgressListener#progressReceived(HighLevelClient,
262          *      String, HighLevelProgress)
263          */
264         public void progressReceived(HighLevelClient highLevelClient, String identifier, HighLevelProgress highLevelProgress) {
265                 Node node = nodeManager.getNode(highLevelClient);
266                 if (node == null) {
267                         logger.warning("got high-level client without node: " + highLevelClient);
268                         return;
269                 }
270                 Map<String, Request> identifierRequests = nodeRequests.get(node);
271                 if (identifierRequests == null) {
272                         logger.warning("got node without request map: " + node);
273                         return;
274                 }
275                 Request request = identifierRequests.get(identifier);
276                 if (request == null) {
277                         logger.warning("got progress for unknown request: " + identifier);
278                         return;
279                 }
280                 request.setTotalBlocks(highLevelProgress.getTotalBlocks());
281                 request.setRequiredBlocks(highLevelProgress.getRequiredBlocks());
282                 request.setSuccessfulBlocks(highLevelProgress.getSuccessfulBlocks());
283                 request.setFailedBlocks(highLevelProgress.getFailedBlocks());
284                 request.setFatallyFailedBlocks(highLevelProgress.getFatallyFailedBlocks());
285                 request.setTotalFinalized(highLevelProgress.isTotalFinalized());
286                 fireRequestProgressed(request);
287         }
288
289 }