Brian O'Connor

Added WITHDRAW_REQ Intent State for ONOS-146

Fixed flow removed from other instance

Change-Id: I22c88a447e26770fea8b7e23f4a78b1389077ad1
Showing 20 changed files with 114 additions and 114 deletions
......@@ -136,7 +136,7 @@ public class FooComponent {
@Override
public void event(IntentEvent event) {
String message;
if (event.type() == IntentEvent.Type.SUBMITTED) {
if (event.type() == IntentEvent.Type.INSTALL_REQ) {
message = "WOW! It looks like someone has some intentions: {}";
} else if (event.type() == IntentEvent.Type.INSTALLED) {
message = "AWESOME! So far things are going great: {}";
......
......@@ -134,7 +134,7 @@ public class IntentMetrics implements IntentMetricsService,
// an event equivalent of "Withdraw Requested"
//
switch (event.type()) {
case SUBMITTED:
case INSTALL_REQ:
intentSubmittedEventMetric.eventReceived();
break;
case INSTALLED:
......
......@@ -31,9 +31,9 @@ public interface IntentMetricsService {
public List<IntentEvent> getEvents();
/**
* Gets the Event Metric for the intent SUBMITTED events.
* Gets the Event Metric for the intent INSTALL_REQ events.
*
* @return the Event Metric for the intent SUBMITTED events.
* @return the Event Metric for the intent INSTALL_REQ events.
*/
public EventMetric intentSubmittedEventMetric();
......
......@@ -94,7 +94,7 @@ public class OpticalPathProvisioner {
@Override
public void event(IntentEvent event) {
switch (event.type()) {
case SUBMITTED:
case INSTALL_REQ:
break;
case INSTALLED:
break;
......
......@@ -245,7 +245,7 @@ public class IntentPushTestCommand extends AbstractShellCommand
} else {
log.warn("install event latch is null");
}
} else if (event.type() != Type.SUBMITTED) {
} else if (event.type() != Type.INSTALL_REQ) {
log.info("Unexpected intent event: {}", event);
}
}
......
......@@ -246,7 +246,7 @@ public class IntentsListCommand extends AbstractShellCommand {
void update(IntentState intentState) {
total++;
switch (intentState) {
case SUBMITTED:
case INSTALL_REQ:
submitted++;
break;
case COMPILING:
......
......@@ -176,7 +176,6 @@ public class DefaultFlowRule implements FlowRule {
if (obj instanceof DefaultFlowRule) {
DefaultFlowRule that = (DefaultFlowRule) obj;
return Objects.equals(deviceId, that.deviceId) &&
Objects.equals(id, that.id) &&
Objects.equals(priority, that.priority) &&
Objects.equals(selector, that.selector);
......
......@@ -24,9 +24,9 @@ public class IntentEvent extends AbstractEvent<IntentEvent.Type, Intent> {
public enum Type {
/**
* Signifies that a new intent has been submitted to the system.
* Signifies that an intent is to be installed or reinstalled.
*/
SUBMITTED,
INSTALL_REQ,
/**
* Signifies that an intent has been successfully installed.
......@@ -39,6 +39,11 @@ public class IntentEvent extends AbstractEvent<IntentEvent.Type, Intent> {
FAILED,
/**
* Signifies that an intent will be withdrawn.
*/
WITHDRAW_REQ,
/**
* Signifies that an intent has been withdrawn from the system.
*/
WITHDRAWN
......@@ -70,12 +75,15 @@ public class IntentEvent extends AbstractEvent<IntentEvent.Type, Intent> {
public static IntentEvent getEvent(IntentState state, Intent intent) {
Type type;
switch (state) {
case SUBMITTED:
type = Type.SUBMITTED;
case INSTALL_REQ:
type = Type.INSTALL_REQ;
break;
case INSTALLED:
type = Type.INSTALLED;
break;
case WITHDRAW_REQ:
type = Type.WITHDRAW_REQ;
break;
case WITHDRAWN:
type = Type.WITHDRAWN;
break;
......
......@@ -26,9 +26,11 @@ public enum IntentState {
* local controller instance.
* <p>
* All intent in the runtime take this state first.
* </p><p>
* Intents will also pass through this state when they are updated.
* </p>
*/
SUBMITTED,
INSTALL_REQ,
/**
* Signifies that the intent is being compiled into installable intents.
......@@ -67,16 +69,11 @@ public enum IntentState {
RECOMPILING,
/**
* TODO: Indicated that an intent will soon be recompiled.
*/
//UPDATE,
/**
* TODO.
* Indicates that an application has requested that an intent be withdrawn.
* It will start withdrawing short, but not necessarily on this instance.
* It will start withdrawing shortly, but not necessarily on this instance.
* Intents can also be parked here if it is impossible to withdraw them.
*/
//WITHDRAW_REQ,
WITHDRAW_REQ,
/**
* Indicates that the intent is being withdrawn. This is a transitional
......
......@@ -174,8 +174,8 @@ public class FakeIntentManager implements TestableIntentService {
@Override
public void submit(Intent intent) {
intents.put(intent.id(), intent);
setState(intent, IntentState.SUBMITTED);
dispatch(new IntentEvent(IntentEvent.Type.SUBMITTED, intent));
setState(intent, IntentState.INSTALL_REQ);
dispatch(new IntentEvent(IntentEvent.Type.INSTALL_REQ, intent));
executeSubmit(intent);
}
......
......@@ -21,7 +21,7 @@ import static org.junit.Assert.assertNull;
import static org.junit.Assert.fail;
import static org.onlab.onos.net.intent.IntentEvent.Type.FAILED;
import static org.onlab.onos.net.intent.IntentEvent.Type.INSTALLED;
import static org.onlab.onos.net.intent.IntentEvent.Type.SUBMITTED;
import static org.onlab.onos.net.intent.IntentEvent.Type.INSTALL_REQ;
import static org.onlab.onos.net.intent.IntentEvent.Type.WITHDRAWN;
import java.util.ArrayList;
......@@ -96,7 +96,7 @@ public class IntentServiceTest {
});
// Make sure that all expected events have been emitted
validateEvents(intent, SUBMITTED, INSTALLED);
validateEvents(intent, INSTALL_REQ, INSTALLED);
// Make sure there is just one intent (and is ours)
assertEquals("incorrect intent count", 1, service.getIntentCount());
......@@ -145,7 +145,7 @@ public class IntentServiceTest {
});
// Make sure that all expected events have been emitted
validateEvents(intent, SUBMITTED, FAILED);
validateEvents(intent, INSTALL_REQ, FAILED);
}
@Test
......@@ -168,7 +168,7 @@ public class IntentServiceTest {
});
// Make sure that all expected events have been emitted
validateEvents(intent, SUBMITTED, FAILED);
validateEvents(intent, INSTALL_REQ, FAILED);
}
/**
......
......@@ -4,9 +4,6 @@ import org.onlab.onos.core.IdBlock;
import org.onlab.onos.core.IdBlockStore;
public class StoreBasedIdBlockAllocator implements IdBlockAllocator {
private long blockTop;
private static final long BLOCK_SIZE = 0x1000000L;
private final IdBlockStore store;
private final String topic;
......
......@@ -38,7 +38,6 @@ import org.onlab.onos.net.intent.IntentBatchDelegate;
import org.onlab.onos.net.intent.IntentBatchService;
import org.onlab.onos.net.intent.IntentCompiler;
import org.onlab.onos.net.intent.IntentEvent;
import org.onlab.onos.net.intent.IntentEvent.Type;
import org.onlab.onos.net.intent.IntentException;
import org.onlab.onos.net.intent.IntentExtensionService;
import org.onlab.onos.net.intent.IntentId;
......@@ -87,6 +86,12 @@ public class IntentManager
private static final int NUM_THREADS = 12;
private static final EnumSet<IntentState> RECOMPILE
= EnumSet.of(INSTALL_REQ, FAILED, WITHDRAW_REQ);
private static final EnumSet<IntentState> NON_PARKED_OR_FAILED
= EnumSet.complementOf(EnumSet.of(INSTALL_REQ, INSTALLED, WITHDRAW_REQ, WITHDRAWN));
// Collections for compiler, installer, and listener are ONOS instance local
private final ConcurrentMap<Class<? extends Intent>,
IntentCompiler<? extends Intent>> compilers = new ConcurrentHashMap<>();
......@@ -510,13 +515,18 @@ public class IntentManager
if (compileAllFailed) {
// If required, compile all currently failed intents.
for (Intent intent : getIntents()) {
if (getIntentState(intent.id()) == FAILED) {
IntentState state = getIntentState(intent.id());
if (RECOMPILE.contains(state)) {
IntentOperations.Builder builder = batches.get(intent.appId());
if (builder == null) {
builder = IntentOperations.builder(intent.appId());
batches.put(intent.appId(), builder);
}
builder.addUpdateOperation(intent.id());
if (state == WITHDRAW_REQ) {
builder.addWithdrawOperation(intent.id());
} else {
builder.addUpdateOperation(intent.id());
}
}
}
}
......@@ -607,15 +617,18 @@ public class IntentManager
} else {
oldInstallables = null;
if (newIntent == null) {
log.info("Ignoring {} for Intent {}", op.type(), op.intentId());
log.info("Ignoring {} for missing Intent {}", op.type(), op.intentId());
}
}
}
void init(BatchWrite batchWrite) {
// add new intent to store (if required)
if (newIntent != null) {
// TODO consider only "creating" intent if it does not exist
// Note: We need to set state to INSTALL_REQ regardless.
batchWrite.createIntent(newIntent);
} else if (oldIntent != null && !oldIntent.equals(newIntent)) {
batchWrite.setState(oldIntent, WITHDRAW_REQ);
}
}
......@@ -637,10 +650,6 @@ public class IntentManager
void setInstallables(List<Intent> installables) {
newInstallables = installables;
//FIXME batch this
//store.setInstallableIntents(newIntent.id(), installables);
}
boolean isComplete() {
......@@ -659,7 +668,6 @@ public class IntentManager
}
void batchFailed() {
// the current batch has failed, so recompile
// remove the current batch and all remaining
for (int i = currentBatch; i < batches.size(); i++) {
......@@ -673,10 +681,10 @@ public class IntentManager
batches.addAll(uninstallIntent(newIntent, newInstallables()));
}
// FIXME: should we try to recompile?
// TODO we might want to try to recompile the new intent
}
// FIXME make sure this is called!!!
// make sure this is called!!!
private void finalizeStates(BatchWrite batchWrite) {
// events to be triggered on successful write
for (Intent intent : stateMap.keySet()) {
......@@ -695,9 +703,10 @@ public class IntentManager
break;
// FALLTHROUGH to default from here
case SUBMITTED:
case INSTALL_REQ:
case COMPILING:
case RECOMPILING:
case WITHDRAW_REQ:
case WITHDRAWN:
case INSTALLED:
default:
......@@ -708,10 +717,6 @@ public class IntentManager
}
}
List<FlowRuleBatchOperation> batches() {
return batches;
}
void addBatches(List<FlowRuleBatchOperation> batches) {
this.batches.addAll(batches);
}
......@@ -720,31 +725,19 @@ public class IntentManager
return stateMap.get(intent);
}
// set transient state during intent update process
void setInflightState(Intent intent, IntentState newState) {
// This method should be called for
// transition to non-parking or Failed only
EnumSet<IntentState> nonParkingOrFailed
= EnumSet.complementOf(EnumSet.of(SUBMITTED, INSTALLED, WITHDRAWN));
if (!nonParkingOrFailed.contains(newState)) {
if (!NON_PARKED_OR_FAILED.contains(newState)) {
log.error("Unexpected transition to {}", newState);
}
// TODO: clean this up, or set to debug
IntentState oldState = stateMap.get(intent);
log.debug("intent id: {}, old state: {}, new state: {}",
intent.id(), oldState, newState);
stateMap.put(intent, newState);
// IntentEvent event = store.setState(intent, newState);
// if (event != null) {
// eventDispatcher.post(event);
// }
}
Map<Intent, IntentState> stateMap() {
return stateMap;
}
}
......@@ -790,12 +783,6 @@ public class IntentManager
// start processing each Intents
for (IntentUpdate update : intentUpdates) {
if (update.newIntent() != null) {
IntentState state = store.getIntentState(update.newIntent().id());
if (state == SUBMITTED) {
eventDispatcher.post(new IntentEvent(Type.SUBMITTED, update.newIntent));
}
}
processIntentUpdate(update);
}
future = applyNextBatch();
......@@ -820,15 +807,11 @@ public class IntentManager
private void updateBatches(CompletedBatchOperation completed) {
if (completed.isSuccess()) {
BatchWrite batchWrite = store.newBatchWrite();
List<IntentEvent> events = new ArrayList<>();
for (IntentUpdate update : intentUpdates) {
update.batchSuccess(batchWrite);
}
if (!batchWrite.isEmpty()) {
store.batchWrite(batchWrite);
for (IntentEvent event : events) {
eventDispatcher.post(event);
}
}
} else {
// entire batch has been reverted...
......@@ -851,6 +834,13 @@ public class IntentManager
}
}
private void abandonShip() {
// the batch has failed
// TODO: maybe we should do more?
future = null;
log.error("Walk the plank, matey...");
}
/**
* Iterate through the pending futures, and remove them when they have completed.
*/
......@@ -863,9 +853,11 @@ public class IntentManager
CompletedBatchOperation completed = future.get(100, TimeUnit.NANOSECONDS);
updateBatches(completed);
future = applyNextBatch();
} catch (TimeoutException | InterruptedException | ExecutionException te) {
//TODO look into error message
log.debug("Installation of intents are still pending: {}", ops);
} catch (TimeoutException | InterruptedException te) {
log.trace("Installation of intents are still pending: {}", ops);
} catch (ExecutionException e) {
log.warn("Execution of batch failed: {}", ops, e);
abandonShip();
}
}
......@@ -893,7 +885,6 @@ public class IntentManager
}
boolean isComplete() {
// TODO: actually check with the intent update?
return future == null;
}
......
......@@ -130,11 +130,11 @@ public class IntentManagerTest {
public void submitIntent() {
flowRuleService.setFuture(true);
listener.setLatch(1, Type.SUBMITTED);
listener.setLatch(1, Type.INSTALL_REQ);
listener.setLatch(1, Type.INSTALLED);
Intent intent = new MockIntent(MockIntent.nextId());
service.submit(intent);
listener.await(Type.SUBMITTED);
listener.await(Type.INSTALL_REQ);
listener.await(Type.INSTALLED);
assertEquals(1L, service.getIntentCount());
assertEquals(1L, flowRuleService.getFlowRuleCount());
......@@ -194,7 +194,7 @@ public class IntentManagerTest {
MockIntent intent2 = new MockIntent(MockIntent.nextId());
listener.setLatch(1, Type.WITHDRAWN);
listener.setLatch(1, Type.SUBMITTED);
listener.setLatch(1, Type.INSTALL_REQ);
listener.setLatch(1, Type.INSTALLED);
service.replace(intent.id(), intent2);
listener.await(Type.WITHDRAWN);
......
......@@ -35,7 +35,7 @@ import java.util.Map;
@Service
public class DistributedIdBlockStore implements IdBlockStore {
private static final long DEFAULT_BLOCK_SIZE = 1000L;
private static final long DEFAULT_BLOCK_SIZE = 0x1000L;
protected Map<String, IAtomicLong> topicBlocks;
......
......@@ -73,12 +73,12 @@ public class DistributedIntentStore
implements IntentStore, MetricsHelper {
/** Valid parking state, which can transition to INSTALLED. */
private static final Set<IntentState> PRE_INSTALLED = EnumSet.of(SUBMITTED, INSTALLED, FAILED);
private static final Set<IntentState> PRE_INSTALLED = EnumSet.of(INSTALL_REQ, INSTALLED, FAILED);
/** Valid parking state, which can transition to WITHDRAWN. */
private static final Set<IntentState> PRE_WITHDRAWN = EnumSet.of(INSTALLED, FAILED);
private static final Set<IntentState> PARKING = EnumSet.of(SUBMITTED, INSTALLED, WITHDRAWN, FAILED);
private static final Set<IntentState> PARKING = EnumSet.of(INSTALL_REQ, INSTALLED, WITHDRAWN, FAILED);
private final Logger log = getLogger(getClass());
......@@ -196,7 +196,7 @@ public class DistributedIntentStore
// duplicate, ignore
return;
} else {
this.setState(intent, IntentState.SUBMITTED);
this.setState(intent, IntentState.INSTALL_REQ);
return;
}
} finally {
......@@ -286,19 +286,19 @@ public class DistributedIntentStore
// parking state transition
switch (state) {
case SUBMITTED:
case INSTALL_REQ:
prevParking = states.get(id);
if (prevParking == null) {
updated = states.putIfAbsent(id, SUBMITTED);
verify(updated, "Conditional replace %s => %s failed", prevParking, SUBMITTED);
updated = states.putIfAbsent(id, INSTALL_REQ);
verify(updated, "Conditional replace %s => %s failed", prevParking, INSTALL_REQ);
} else {
verify(prevParking == WITHDRAWN,
"Illegal state transition attempted from %s to SUBMITTED",
"Illegal state transition attempted from %s to INSTALL_REQ",
prevParking);
updated = states.replace(id, prevParking, SUBMITTED);
verify(updated, "Conditional replace %s => %s failed", prevParking, SUBMITTED);
updated = states.replace(id, prevParking, INSTALL_REQ);
verify(updated, "Conditional replace %s => %s failed", prevParking, INSTALL_REQ);
}
evtType = IntentEvent.Type.SUBMITTED;
evtType = IntentEvent.Type.INSTALL_REQ;
break;
case INSTALLED:
......@@ -430,8 +430,8 @@ public class DistributedIntentStore
"CREATE_INTENT takes 1 argument. %s", op);
Intent intent = op.arg(0);
builder.putIfAbsent(INTENTS_TABLE, strIntentId(intent.id()), serializer.encode(intent));
builder.putIfAbsent(STATES_TABLE, strIntentId(intent.id()), serializer.encode(SUBMITTED));
events.add(IntentEvent.getEvent(SUBMITTED, intent));
builder.putIfAbsent(STATES_TABLE, strIntentId(intent.id()), serializer.encode(INSTALL_REQ));
events.add(IntentEvent.getEvent(INSTALL_REQ, intent));
break;
case REMOVE_INTENT:
......
......@@ -72,12 +72,12 @@ public class HazelcastIntentStore
implements IntentStore, MetricsHelper {
/** Valid parking state, which can transition to INSTALLED. */
private static final Set<IntentState> PRE_INSTALLED = EnumSet.of(SUBMITTED, INSTALLED, FAILED);
private static final Set<IntentState> PRE_INSTALLED = EnumSet.of(INSTALL_REQ, INSTALLED, FAILED);
/** Valid parking state, which can transition to WITHDRAWN. */
private static final Set<IntentState> PRE_WITHDRAWN = EnumSet.of(INSTALLED, FAILED);
private static final Set<IntentState> PARKING = EnumSet.of(SUBMITTED, INSTALLED, WITHDRAWN, FAILED);
private static final Set<IntentState> PARKING = EnumSet.of(INSTALL_REQ, INSTALLED, WITHDRAWN, FAILED);
private final Logger log = getLogger(getClass());
......@@ -150,7 +150,7 @@ public class HazelcastIntentStore
IMap<byte[], byte[]> rawStates = super.theInstance.getMap("intent-states");
states = new SMap<>(rawStates , super.serializer);
EntryListener<IntentId, IntentState> listener = new RemoteIntentStateListener();
states.addEntryListener(listener , false);
states.addEntryListener(listener , true);
transientStates.clear();
......@@ -180,7 +180,7 @@ public class HazelcastIntentStore
// duplicate, ignore
return;
} else {
this.setState(intent, IntentState.SUBMITTED);
this.setState(intent, IntentState.INSTALL_REQ);
return;
}
} finally {
......@@ -261,7 +261,6 @@ public class HazelcastIntentStore
public void setState(Intent intent, IntentState state) {
Context timer = startTimer(setStateTimer);
try {
final IntentId id = intent.id();
IntentEvent.Type type = null;
final IntentState prevParking;
......@@ -269,23 +268,23 @@ public class HazelcastIntentStore
// parking state transition
switch (state) {
case SUBMITTED:
case INSTALL_REQ:
prevParking = states.get(id);
if (prevParking == null) {
IntentState existing = states.putIfAbsent(id, SUBMITTED);
verify(existing == null, "Conditional replace %s => %s failed", prevParking, SUBMITTED);
IntentState existing = states.putIfAbsent(id, INSTALL_REQ);
verify(existing == null, "Conditional replace %s => %s failed", prevParking, INSTALL_REQ);
} else {
verify(prevParking == WITHDRAWN,
"Illegal state transition attempted from %s to SUBMITTED",
verify(PRE_INSTALLED.contains(prevParking),
"Illegal state transition attempted from %s to INSTALL_REQ",
prevParking);
boolean updated = states.replace(id, prevParking, SUBMITTED);
verify(updated, "Conditional replace %s => %s failed", prevParking, SUBMITTED);
boolean updated = states.replace(id, prevParking, INSTALL_REQ);
verify(updated, "Conditional replace %s => %s failed", prevParking, INSTALL_REQ);
}
type = IntentEvent.Type.SUBMITTED;
type = IntentEvent.Type.INSTALL_REQ;
break;
case INSTALLED:
prevParking = states.replace(id, INSTALLED);
verify(PRE_INSTALLED.contains(prevParking),
verify(prevParking == INSTALL_REQ,
"Illegal state transition attempted from %s to INSTALLED",
prevParking);
type = IntentEvent.Type.INSTALLED;
......@@ -294,9 +293,16 @@ public class HazelcastIntentStore
prevParking = states.replace(id, FAILED);
type = IntentEvent.Type.FAILED;
break;
case WITHDRAW_REQ:
prevParking = states.replace(id, WITHDRAW_REQ);
verify(PRE_WITHDRAWN.contains(prevParking),
"Illegal state transition attempted from %s to WITHDRAW_REQ",
prevParking);
type = IntentEvent.Type.WITHDRAW_REQ;
break;
case WITHDRAWN:
prevParking = states.replace(id, WITHDRAWN);
verify(PRE_WITHDRAWN.contains(prevParking),
verify(prevParking == WITHDRAW_REQ,
"Illegal state transition attempted from %s to WITHDRAWN",
prevParking);
type = IntentEvent.Type.WITHDRAWN;
......@@ -316,7 +322,6 @@ public class HazelcastIntentStore
if (type != null) {
notifyDelegate(new IntentEvent(type, intent));
}
return;
} finally {
stopTimer(timer);
}
......@@ -370,7 +375,7 @@ public class HazelcastIntentStore
Intent intent = op.arg(0);
futures.add(Pair.of(op,
ImmutableList.of(intents.putAsync(intent.id(), intent),
states.putAsync(intent.id(), SUBMITTED))));
states.putAsync(intent.id(), INSTALL_REQ))));
break;
case REMOVE_INTENT:
......@@ -426,7 +431,7 @@ public class HazelcastIntentStore
case CREATE_INTENT:
{
Intent intent = op.arg(0);
IntentState newIntentState = SUBMITTED;
IntentState newIntentState = INSTALL_REQ;
try {
Intent prevIntent = (Intent) subops.get(0).get();
......@@ -437,7 +442,7 @@ public class HazelcastIntentStore
prevIntent, prevIntentState,
intent, newIntentState);
}
events.add(IntentEvent.getEvent(SUBMITTED, intent));
events.add(IntentEvent.getEvent(INSTALL_REQ, intent));
} catch (InterruptedException e) {
log.error("Batch write was interrupted while processing {}", op, e);
failed.add(op);
......
......@@ -31,7 +31,7 @@ import java.util.concurrent.atomic.AtomicLong;
@Service
public class SimpleIdBlockStore implements IdBlockStore {
private static final long DEFAULT_BLOCK_SIZE = 1000L;
private static final long DEFAULT_BLOCK_SIZE = 0x1000L;
private final Map<String, AtomicLong> topicBlocks = new ConcurrentHashMap<>();
......
......@@ -69,8 +69,7 @@ public class SimpleIntentStore
return;
}
intents.put(intent.id(), intent);
this.setState(intent, IntentState.SUBMITTED);
return;
this.setState(intent, IntentState.INSTALL_REQ);
}
@Override
......@@ -109,8 +108,8 @@ public class SimpleIntentStore
IntentEvent.Type type = null;
switch (state) {
case SUBMITTED:
type = IntentEvent.Type.SUBMITTED;
case INSTALL_REQ:
type = IntentEvent.Type.INSTALL_REQ;
break;
case INSTALLED:
type = IntentEvent.Type.INSTALLED;
......@@ -118,6 +117,9 @@ public class SimpleIntentStore
case FAILED:
type = IntentEvent.Type.FAILED;
break;
case WITHDRAW_REQ:
type = IntentEvent.Type.WITHDRAW_REQ;
break;
case WITHDRAWN:
type = IntentEvent.Type.WITHDRAWN;
break;
......
......@@ -59,6 +59,7 @@ public class SimpleLeadershipManager implements LeadershipService {
@Override
public Map<String, Leadership> getLeaderBoard() {
//FIXME
throw new UnsupportedOperationException("I don't know what to do." +
" I wish you luck.");
}
......