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