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