--- /dev/null
+/*
+ * jSite2 - FcpCollector.java -
+ * Copyright © 2008 David Roden
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+package net.pterodactylus.jsite.freenet;
+
+import java.io.IOException;
+import java.net.UnknownHostException;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import net.pterodactylus.fcp.highlevel.ConnectResult;
+import net.pterodactylus.fcp.highlevel.HighLevelCallback;
+import net.pterodactylus.fcp.highlevel.HighLevelClient;
+import net.pterodactylus.jsite.core.Node;
+
+/**
+ * TODO
+ *
+ * @author David ‘Bombe’ Roden <bombe@freenetproject.org>
+ * @version $Id$
+ */
+public class FcpCollector {
+
+ /** The FCP client name. */
+ private final String clientName;
+
+ /** Object used for synchronization. */
+ private final Object syncObject = new Object();
+
+ /** All FCP connections. */
+ private Set<HighLevelClient> connections = Collections.synchronizedSet(new HashSet<HighLevelClient>());
+
+ /** Keeps track of which connection is in use right now. */
+ private Set<HighLevelClient> usedConnections = Collections.synchronizedSet(new HashSet<HighLevelClient>());
+
+ /** Maps nodes to high-level clients. */
+ private Map<HighLevelClient, Node> clientNodes = Collections.synchronizedMap(new HashMap<HighLevelClient, Node>());
+
+ /**
+ * Creates a new FCP collector.
+ *
+ * @param clientName
+ * The name of the FCP client
+ */
+ public FcpCollector(String clientName) {
+ this.clientName = clientName;
+ }
+
+ //
+ // ACTIONS
+ //
+
+ /**
+ * Adds a connection to the given node. The connection is made instantly so
+ * this method may block.
+ *
+ * @param node
+ * The node to connect to
+ * @return <code>true</code> if the connection to the node could be
+ * established
+ * @throws UnknownHostException
+ * if the hostname of the node can not be resolved
+ * @throws IOException
+ * if an I/O error occurs connecting to the node
+ */
+ public boolean addNode(Node node) throws UnknownHostException, IOException {
+ HighLevelClient highLevelClient = new HighLevelClient(clientName, node.getHostname(), node.getPort());
+ HighLevelCallback<ConnectResult> connectCallback = highLevelClient.connect();
+ ConnectResult connectResult = null;
+ while (connectResult == null) {
+ try {
+ connectResult = connectCallback.getResult();
+ } catch (InterruptedException e) {
+ /* ignore. */
+ }
+ }
+ if (connectResult.isConnected()) {
+ synchronized (syncObject) {
+ connections.add(highLevelClient);
+ clientNodes.put(highLevelClient, node);
+ }
+ }
+ return connectResult.isConnected();
+ }
+
+ /**
+ * Returns a list of all nodes.
+ *
+ * @return A list of all nodes
+ */
+ public List<Node> getNodes() {
+ return new ArrayList<Node>(clientNodes.values());
+ }
+
+ //
+ // PRIVATE METHODS
+ //
+
+ /**
+ * Finds a currently unused high-level client, optionally waiting until a
+ * client is free and marking it used.
+ *
+ * @param wait
+ * <code>true</code> to wait for a free connection,
+ * <code>false</code> to return <code>null</code>
+ * @param markAsUsed
+ * <code>true</code> to mark the connection as used before
+ * returning it, <code>false</code> not to mark it
+ * @return An unused FCP connection, or <code>null</code> if no connection
+ * could be found
+ */
+ @SuppressWarnings("unused")
+ private HighLevelClient findUnusedClient(boolean wait, boolean markAsUsed) {
+ synchronized (syncObject) {
+ HighLevelClient freeHighLevelClient = null;
+ while (freeHighLevelClient == null) {
+ for (HighLevelClient highLevelClient: connections) {
+ if (!usedConnections.contains(highLevelClient)) {
+ freeHighLevelClient = highLevelClient;
+ break;
+ }
+ }
+ if (freeHighLevelClient != null) {
+ if (markAsUsed) {
+ usedConnections.add(freeHighLevelClient);
+ }
+ return freeHighLevelClient;
+ }
+ if (!wait) {
+ return null;
+ }
+ }
+ /* we never get here, but the compiler doesn't realize. */
+ return null;
+ }
+ }
+
+}