/*
* Copyright 2009 Thomas Bocek
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
package net.tomp2p.futures;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Set;
import net.tomp2p.message.TrackerData;
import net.tomp2p.p2p.EvaluatingSchemeTracker;
import net.tomp2p.p2p.VotingSchemeTracker;
import net.tomp2p.peers.Number160;
import net.tomp2p.peers.PeerAddress;
/**
* This class holds the object for future results from the tracker get() and
* add(). FutureTracker can fail, if the search did not return any results.
*
* @author Thomas Bocek
*/
public class FutureTracker extends BaseFutureImpl<FutureTracker> {
// since we receive results from multiple peers, we need to summarize them
final private EvaluatingSchemeTracker evaluatingSchemeTracker;
// a set of know peers that we don't want in the result set.
final private Set<Number160> knownPeers;
// keeps track of futures that are based on this future
final private FutureCreate<BaseFuture> futureCreate;
final private List<Cancel> cleanup = new ArrayList<Cancel>(1);
// results
private Set<PeerAddress> potentialTrackers;
private Set<PeerAddress> directTrackers;
private Map<PeerAddress, TrackerData> peersOnTracker;
public FutureTracker() {
this(null);
}
/**
* Create a future object for storing
*
* @param futureCreate
* Keeps track of futures that are based on this future
*/
public FutureTracker(FutureCreate<BaseFuture> futureCreate) {
this(new VotingSchemeTracker(), null, futureCreate);
}
/**
* Create a future object for retrieving.
*
* @param evaluatingSchemeTracker
* Since we receive results from multiple peers, we need to
* summarize them
* @param knownPeers
* A set of know peers that we don't want in the result set.
*/
public FutureTracker(EvaluatingSchemeTracker evaluatingSchemeTracker, Set<Number160> knownPeers) {
this(new VotingSchemeTracker(), knownPeers, null);
}
/**
* Sets all the values for this future object.
*
* @param evaluatingSchemeTracker
* Since we receive results from multiple peers, we need to
* summarize them
* @param knownPeers
* A set of know peers that we don't want in the result set.
* @param futureCreate
* Keeps track of futures that are based on this future
*/
private FutureTracker(EvaluatingSchemeTracker evaluatingSchemeTracker, Set<Number160> knownPeers,
FutureCreate<BaseFuture> futureCreate) {
this.evaluatingSchemeTracker = evaluatingSchemeTracker;
this.knownPeers = knownPeers;
this.futureCreate = futureCreate;
self(this);
}
/**
* Called if a future is created based on this future.
*
* @param future
* The newly created future
*/
public void repeated(BaseFuture future) {
if (futureCreate != null)
futureCreate.repeated(future);
}
/**
* Set the result of the tracker process.
*
* @param potentialTrackers
* The trackers that are close to the key, also containing the
* direct trackers.
* @param directTrackers
* Those peers that are close and reported to have the key.
* @param peersOnTracker
* The data from the trackers.
*/
public void setTrackers(Set<PeerAddress> potentialTrackers, Set<PeerAddress> directTrackers,
Map<PeerAddress, TrackerData> peersOnTracker) {
synchronized (lock) {
if (!setCompletedAndNotify())
return;
this.potentialTrackers = potentialTrackers;
this.directTrackers = directTrackers;
this.peersOnTracker = peersOnTracker;
this.type = ((potentialTrackers.size() == 0) && (directTrackers.size() == 0)) ? BaseFuture.FutureType.FAILED
: BaseFuture.FutureType.OK;
if (this.type == BaseFuture.FutureType.FAILED) {
this.reason = "we did not find anything, are you sure you are serching for the right tracker?";
}
}
notifyListerenrs();
}
/**
* @return The trackers that are close to the key, also containing the
* direct trackers.
*/
public Set<PeerAddress> getPotentialTrackers() {
synchronized (lock) {
return potentialTrackers;
}
}
/**
* @return Those peers that are close and reported to have the key.
*/
public Set<PeerAddress> getDirectTrackers() {
synchronized (lock) {
return directTrackers;
}
}
/**
* @return the raw data, which means all the data the trackers reported.
*/
public Map<PeerAddress, TrackerData> getRawPeersOnTracker() {
synchronized (lock) {
return peersOnTracker;
}
}
/**
* @return The peer address that send back data.
*/
public Set<PeerAddress> getPeersOnTracker() {
synchronized (lock) {
return peersOnTracker.keySet();
}
}
/**
* @return The list of peers which we already have in our result set.
*/
public Set<Number160> getKnownPeers() {
synchronized (lock) {
return knownPeers;
}
}
/**
* Evaluates the data from the trackers. Since we receive multiple results,
* we evaluate them before we give the data to the user. If the user wants
* to see the raw data, use {@link #getRawPeersOnTracker()}.
*
* @return The data from the trackers.
*/
public Collection<TrackerData> getTrackers() {
synchronized (lock) {
return evaluatingSchemeTracker.evaluateSingle(peersOnTracker);
}
}
public void addCleanup(Cancel cancellable) {
synchronized (lock) {
cleanup.add(cancellable);
}
}
public void shutdown() {
// Even though, this future is completed, there may be tasks than can be
// canceled due to scheduled futures attached to this event.
synchronized (lock) {
for (final Cancel cancellable : cleanup) {
cancellable.cancel();
}
}
}
}