WIP
[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.Set;
29 import java.util.logging.Level;
30 import java.util.logging.Logger;
31
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.RequestListResult;
38 import net.pterodactylus.fcp.highlevel.RequestResult;
39 import net.pterodactylus.util.logging.Logging;
40
41 /**
42  * The request manager keeps track of all the request on all connected nodes.
43  * The request manager is added to the {@link NodeManager} as a
44  * {@link NodeListener} so that it can fire request-removed events in case a
45  * node is disconnected.
46  * 
47  * @author David ‘Bombe’ Roden <bombe@freenetproject.org>
48  * @version $Id$
49  */
50 public class RequestManager implements NodeListener, HighLevelProgressListener {
51
52         /** Logger. */
53         private static final Logger logger = Logging.getLogger(RequestManager.class.getName());
54
55         /** Request listeners. */
56         private List<RequestListener> requestListeners = Collections.synchronizedList(new ArrayList<RequestListener>());
57
58         /** The node manager. */
59         private NodeManager nodeManager;
60
61         /** Request lists for all nodes. */
62         @SuppressWarnings("unused")
63         private Map<Node, Set<Request>> nodeRequests = Collections.synchronizedMap(new HashMap<Node, Set<Request>>());
64
65         //
66         // EVENT MANAGEMENT
67         //
68
69         /**
70          * Adds a request listener.
71          * 
72          * @param requestListener
73          *            The request listener to add
74          */
75         public void addRequestListener(RequestListener requestListener) {
76                 requestListeners.add(requestListener);
77         }
78
79         /**
80          * Removes a request listener.
81          * 
82          * @param requestListener
83          *            The request listener to remove
84          */
85         public void removeRequestListener(RequestListener requestListener) {
86                 requestListeners.remove(requestListener);
87         }
88
89         /**
90          * Notifies all listeners that a request was added.
91          * 
92          * @param node
93          *            The node that added the request
94          * @param request
95          *            The request that was added
96          */
97         private void fireRequestAdded(Node node, Request request) {
98                 for (RequestListener requestListener: requestListeners) {
99                         requestListener.requestAdded(node, request);
100                 }
101         }
102
103         /**
104          * Notifies all listeners that a request progressed.
105          * 
106          * @param node
107          *            The node that runs the request
108          * @param request
109          *            The request
110          * @param totalBlocks
111          *            The total number of blocks
112          * @param requiredBlocks
113          *            The number of required blocks
114          * @param successfulBlocks
115          *            The number of successful blocks
116          * @param failedBlocks
117          *            The number of failed blocks
118          * @param fatallyFailedBlocks
119          *            The number of fatally failed blocks
120          * @param finalizedTotal
121          *            <code>true</code> if the total number of blocks in final,
122          *            <code>false</code> otherwise
123          */
124         private void fireRequestProgressed(Node node, Request request, int totalBlocks, int requiredBlocks, int successfulBlocks, int failedBlocks, int fatallyFailedBlocks, boolean finalizedTotal) {
125                 for (RequestListener requestListener: requestListeners) {
126                         requestListener.requestProgressed(node, request, totalBlocks, requiredBlocks, successfulBlocks, failedBlocks, fatallyFailedBlocks, finalizedTotal);
127                 }
128         }
129
130         //
131         // ACCESSORS
132         //
133
134         /**
135          * Sets the node manager to use.
136          * 
137          * @param nodeManager
138          *            The node manager
139          */
140         public void setNodeManager(NodeManager nodeManager) {
141                 this.nodeManager = nodeManager;
142         }
143
144         //
145         // ACTIONS
146         //
147
148         //
149         // PRIVATE ACTIONS
150         //
151
152         /**
153          * Requests a list of all running requests from a node. This method will
154          * block until the request has been sent!
155          * 
156          * @param node
157          *            The node to get all requests for
158          * @throws IOException
159          *             if an I/O error occurs while communicating with the node
160          */
161         private void getRequests(final Node node) throws IOException {
162                 HighLevelClient highLevelClient = nodeManager.borrowHighLevelClient(node);
163                 if (highLevelClient == null) {
164                         logger.log(Level.WARNING, "no client for node: " + node);
165                         return;
166                 }
167                 try {
168                         HighLevelCallback<RequestListResult> requestListCallback = highLevelClient.getRequests();
169                         requestListCallback.addHighLevelCallbackListener(new HighLevelCallbackListener<RequestListResult>() {
170
171                                 @SuppressWarnings("synthetic-access")
172                                 public void gotResult(HighLevelCallback<RequestListResult> highLevelCallback) {
173                                         RequestListResult requestListResult;
174                                         try {
175                                                 requestListResult = highLevelCallback.getResult();
176                                         } catch (InterruptedException e) {
177                                                 logger.log(Level.SEVERE, "getResult() blocked and was interrupted");
178                                                 return;
179                                         }
180                                         for (RequestResult requestResult: requestListResult) {
181                                                 Request request = new Request(requestResult.getIdentifier());
182                                                 /* TODO - fill request */
183                                                 fireRequestAdded(node, request);
184                                         }
185                                 }
186                         });
187                 } finally {
188                         nodeManager.returnHighLevelClient(highLevelClient);
189                 }
190         }
191
192         //
193         // INTERFACE NodeListener
194         //
195
196         /**
197          * {@inheritDoc}
198          */
199         public void nodeAdded(Node node) {
200                 HighLevelClient highLevelClient = nodeManager.borrowHighLevelClient(node);
201                 if (highLevelClient == null) {
202                         return;
203                 }
204                 try {
205                         highLevelClient.addHighLevelProgressListener(this);
206                 } finally {
207                         nodeManager.returnHighLevelClient(highLevelClient);
208                 }
209         }
210
211         /**
212          * {@inheritDoc}
213          */
214         public void nodeRemoved(Node node) {
215                 /* ignore. */
216         }
217
218         /**
219          * {@inheritDoc}
220          */
221         public void nodeConnected(Node node) {
222                 HighLevelClient highLevelClient = nodeManager.borrowHighLevelClient(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                 } catch (IOException ioe1) {
230                         /* ignore exception, disconnects are handled elsewhere. */
231                 } finally {
232                         nodeManager.returnHighLevelClient(highLevelClient);
233                 }
234                 try {
235                         getRequests(node);
236                 } catch (IOException e) {
237                         /* ignore exception, disconnects are handled elsewhere. */
238                 }
239         }
240
241         /**
242          * {@inheritDoc}
243          */
244         public void nodeDisconnected(Node node, Throwable throwable) {
245                 /* TODO - remove all requests. */
246         }
247
248         //
249         // INTERFACE HighLevelProgressListener
250         //
251
252         /**
253          * @see net.pterodactylus.fcp.highlevel.HighLevelProgressListener#progressReceived(java.lang.String,
254          *      net.pterodactylus.fcp.highlevel.HighLevelProgress)
255          */
256         public void progressReceived(String identifier, HighLevelProgress highLevelProgress) {
257                 fireRequestProgressed(null, new Request(identifier), highLevelProgress.getTotalBlocks(), highLevelProgress.getRequiredBlocks(), highLevelProgress.getSuccessfulBlocks(), highLevelProgress.getFailedBlocks(), highLevelProgress.getFatallyFailedBlocks(), highLevelProgress.isTotalFinalized());
258         }
259
260 }