Remove some unnecessary warnings.
[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.GetRequestResult;
32 import net.pterodactylus.fcp.highlevel.HighLevelCallback;
33 import net.pterodactylus.fcp.highlevel.HighLevelCallbackListener;
34 import net.pterodactylus.fcp.highlevel.HighLevelClient;
35 import net.pterodactylus.fcp.highlevel.HighLevelException;
36 import net.pterodactylus.fcp.highlevel.HighLevelProgress;
37 import net.pterodactylus.fcp.highlevel.HighLevelProgressListener;
38 import net.pterodactylus.fcp.highlevel.PutDirRequestResult;
39 import net.pterodactylus.fcp.highlevel.PutRequestResult;
40 import net.pterodactylus.fcp.highlevel.RequestListResult;
41 import net.pterodactylus.fcp.highlevel.RequestResult;
42 import net.pterodactylus.jsite.core.Request.Type;
43 import net.pterodactylus.util.logging.Logging;
44
45 /**
46  * The request manager keeps track of all the request on all connected nodes.
47  * The request manager is added to the {@link NodeManager} as a
48  * {@link NodeListener} so that it can fire request-removed events in case a
49  * node is disconnected.
50  *
51  * @author David ‘Bombe’ Roden <bombe@freenetproject.org>
52  */
53 public class RequestManager implements NodeListener, HighLevelProgressListener {
54
55         /** Logger. */
56         private static final Logger logger = Logging.getLogger(RequestManager.class.getName());
57
58         /** Request listeners. */
59         private List<RequestListener> requestListeners = Collections.synchronizedList(new ArrayList<RequestListener>());
60
61         /** The node manager. */
62         private NodeManager nodeManager;
63
64         /** Request lists for all nodes. */
65         private Map<Node, Map<String, Request>> nodeRequests = Collections.synchronizedMap(new HashMap<Node, Map<String, Request>>());
66
67         //
68         // EVENT MANAGEMENT
69         //
70
71         /**
72          * Adds a request listener.
73          *
74          * @param requestListener
75          *            The request listener to add
76          */
77         public void addRequestListener(RequestListener requestListener) {
78                 requestListeners.add(requestListener);
79         }
80
81         /**
82          * Removes a request listener.
83          *
84          * @param requestListener
85          *            The request listener to remove
86          */
87         public void removeRequestListener(RequestListener requestListener) {
88                 requestListeners.remove(requestListener);
89         }
90
91         /**
92          * Notifies all listeners that a request was added.
93          *
94          * @param request
95          *            The request that was added
96          */
97         private void fireRequestAdded(Request request) {
98                 for (RequestListener requestListener : requestListeners) {
99                         requestListener.requestAdded(request);
100                 }
101         }
102
103         /**
104          * Notifies all listeners that a request progressed.
105          *
106          * @param request
107          *            The request
108          */
109         private void fireRequestProgressed(Request request) {
110                 for (RequestListener requestListener : requestListeners) {
111                         requestListener.requestProgressed(request);
112                 }
113         }
114
115         /**
116          * Notifies all listeners that a request was removed.
117          *
118          * @param request
119          *            The request that was removed
120          */
121         private void fireRequestRemoved(Request request) {
122                 for (RequestListener requestListener : requestListeners) {
123                         requestListener.requestRemoved(request);
124                 }
125         }
126
127         /**
128          * Notifies all listeners that a request has finished.
129          *
130          * @see RequestListener#requestFinished(Request)
131          * @param request
132          *            The request that has finished
133          */
134         private void fireRequestFinished(Request request) {
135                 for (RequestListener requestListener : requestListeners) {
136                         requestListener.requestFinished(request);
137                 }
138         }
139
140         /**
141          * Notifies all listeners that a request has generated a URI.
142          *
143          * @see RequestListener#requestGeneratedURI(Request, String)
144          * @param request
145          *            The request that has generated a URI
146          * @param uri
147          *            The generated URI
148          */
149         private void fireRequestGeneratedURI(Request request, String uri) {
150                 for (RequestListener requestListener : requestListeners) {
151                         requestListener.requestGeneratedURI(request, uri);
152                 }
153         }
154
155         //
156         // ACCESSORS
157         //
158
159         /**
160          * Sets the node manager to use.
161          *
162          * @param nodeManager
163          *            The node manager
164          */
165         public void setNodeManager(NodeManager nodeManager) {
166                 this.nodeManager = nodeManager;
167         }
168
169         //
170         // ACTIONS
171         //
172
173         //
174         // PRIVATE ACTIONS
175         //
176
177         /**
178          * Requests a list of all running requests from a node. This method will
179          * block until the request has been sent!
180          *
181          * @param node
182          *            The node to get all requests for
183          * @throws IOException
184          *             if an I/O error occurs while communicating with the node
185          * @throws JSiteException
186          *             if there is a problem with the node
187          */
188         private void getRequests(final Node node) throws IOException, JSiteException {
189                 HighLevelClient highLevelClient = nodeManager.getHighLevelClient(node);
190                 if (highLevelClient == null) {
191                         logger.log(Level.WARNING, "no client for node: " + node);
192                         return;
193                 }
194                 final Map<String, Request> identifierRequests = Collections.synchronizedMap(new HashMap<String, Request>());
195                 nodeRequests.put(node, identifierRequests);
196                 HighLevelCallback<RequestListResult> requestListCallback;
197                 try {
198                         requestListCallback = highLevelClient.getRequests();
199                         requestListCallback.addHighLevelCallbackListener(new HighLevelCallbackListener<RequestListResult>() {
200
201                                 @SuppressWarnings("synthetic-access")
202                                 public void gotResult(HighLevelCallback<RequestListResult> highLevelCallback) {
203                                         RequestListResult requestListResult;
204                                         try {
205                                                 requestListResult = highLevelCallback.getResult();
206                                         } catch (InterruptedException e) {
207                                                 logger.log(Level.SEVERE, "getResult() blocked and was interrupted");
208                                                 return;
209                                         }
210                                         for (RequestResult requestResult : requestListResult) {
211                                                 String identifier = requestResult.getIdentifier();
212                                                 logger.log(Level.FINER, "got identifier: " + identifier);
213                                                 Request request = identifierRequests.get(identifier);
214                                                 if (request == null) {
215                                                         request = new Request(node, identifier);
216                                                 }
217                                                 if (request.getType() == null) {
218                                                         if (requestResult instanceof GetRequestResult) {
219                                                                 request.setType(Type.get);
220                                                         } else if (requestResult instanceof PutRequestResult) {
221                                                                 request.setType(Type.put);
222                                                         } else if (requestResult instanceof PutDirRequestResult) {
223                                                                 request.setType(Type.putDir);
224                                                         }
225                                                 }
226                                                 if (identifierRequests.containsKey(identifier)) {
227                                                         continue;
228                                                 }
229                                                 identifierRequests.put(requestResult.getIdentifier(), request);
230                                                 fireRequestAdded(request);
231                                         }
232                                 }
233                         });
234                 } catch (HighLevelException hle1) {
235                         throw new BackendException(hle1);
236                 }
237         }
238
239         //
240         // INTERFACE NodeListener
241         //
242
243         /**
244          * {@inheritDoc}
245          */
246         public void nodeAdded(Node node) {
247                 HighLevelClient highLevelClient = nodeManager.getHighLevelClient(node);
248                 if (highLevelClient == null) {
249                         logger.warning("got nodeAdded but no high-level client: " + node);
250                         return;
251                 }
252                 highLevelClient.addHighLevelProgressListener(this);
253         }
254
255         /**
256          * {@inheritDoc}
257          */
258         public void nodeRemoved(Node node) {
259                 HighLevelClient highLevelClient = nodeManager.getHighLevelClient(node);
260                 if (highLevelClient == null) {
261                         logger.warning("got nodeRemoved but no high-level client: " + node);
262                         return;
263                 }
264                 highLevelClient.removeHighLevelProgressListener(this);
265         }
266
267         /**
268          * {@inheritDoc}
269          */
270         public void nodeConnected(Node node) {
271                 HighLevelClient highLevelClient = nodeManager.getHighLevelClient(node);
272                 if (highLevelClient == null) {
273                         logger.log(Level.WARNING, "got no high-level client for node " + node);
274                         return;
275                 }
276                 try {
277                         highLevelClient.setWatchGlobal(true);
278                         getRequests(node);
279                 } catch (HighLevelException hle1) {
280                         logger.log(Level.WARNING, "error in backend", hle1);
281                 } catch (JSiteException jse1) {
282                         logger.log(Level.WARNING, "error in backend", jse1);
283                 } catch (IOException e) {
284                         /* ignore exception, disconnects are handled elsewhere. */
285                 }
286         }
287
288         /**
289          * {@inheritDoc}
290          */
291         public void nodeConnectionFailed(Node node, Throwable cause) {
292                 /* we don't care about this. */
293         }
294
295         /**
296          * {@inheritDoc}
297          */
298         public void nodeDisconnected(Node node, Throwable throwable) {
299                 Map<String, Request> identifierRequests = nodeRequests.get(node);
300                 if (identifierRequests == null) {
301                         logger.warning("got node without request map: " + node);
302                         return;
303                 }
304                 for (Request request : identifierRequests.values()) {
305                         fireRequestRemoved(request);
306                 }
307                 identifierRequests.clear();
308         }
309
310         //
311         // INTERFACE HighLevelProgressListener
312         //
313
314         /**
315          * @see net.pterodactylus.fcp.highlevel.HighLevelProgressListener#progressReceived(HighLevelClient,
316          *      String, HighLevelProgress)
317          */
318         public void progressReceived(HighLevelClient highLevelClient, String identifier, HighLevelProgress highLevelProgress) {
319                 Node node = nodeManager.getNode(highLevelClient);
320                 if (node == null) {
321                         logger.warning("got high-level client without node: " + highLevelClient);
322                         return;
323                 }
324                 Map<String, Request> identifierRequests = nodeRequests.get(node);
325                 if (identifierRequests == null) {
326                         logger.warning("got node without request map: " + node);
327                         identifierRequests = Collections.synchronizedMap(new HashMap<String, Request>());
328                         nodeRequests.put(node, identifierRequests);
329                 }
330                 Request request = identifierRequests.get(identifier);
331                 if (request == null) {
332                         logger.warning("got progress for unknown request: " + identifier);
333                         request = new Request(node, identifier);
334                         identifierRequests.put(identifier, request);
335                         fireRequestAdded(request);
336                 }
337                 if (highLevelProgress.isFinished()) {
338                         request.setFinished(true);
339                         request.setSuccessful(!highLevelProgress.isFailed());
340                         fireRequestFinished(request);
341                 } else if (highLevelProgress.isFetchable()) {
342                         /* TODO - ignore? */
343                 } else if (highLevelProgress.getURI() != null) {
344                         request.setURI(highLevelProgress.getURI());
345                         fireRequestGeneratedURI(request, highLevelProgress.getURI());
346                 } else {
347                         request.setTotalBlocks(highLevelProgress.getTotalBlocks());
348                         request.setRequiredBlocks(highLevelProgress.getRequiredBlocks());
349                         request.setSuccessfulBlocks(highLevelProgress.getSuccessfulBlocks());
350                         request.setFailedBlocks(highLevelProgress.getFailedBlocks());
351                         request.setFatallyFailedBlocks(highLevelProgress.getFatallyFailedBlocks());
352                         request.setTotalFinalized(highLevelProgress.isTotalFinalized());
353                         fireRequestProgressed(request);
354                 }
355         }
356
357 }