org.aktivecortex.core.notification.ProgressEvaluatorBuilder Maven / Gradle / Ivy
/*
* Copyright (C) 2012-2013. Aktive Cortex
*
* 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 org.aktivecortex.core.notification;
import org.aktivecortex.api.command.Command;
import org.aktivecortex.api.notification.ProgressEvaluator;
import org.aktivecortex.dbc.assertion.Contract;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import static com.google.common.collect.Sets.intersection;
import static com.google.common.collect.Sets.newHashSet;
import static java.math.BigDecimal.ROUND_HALF_UP;
/**
* A builder for creating {@link ProgressEvaluator} instance.
* Example: {@code
*
* private static final ProgressEvaluator BANK_TRANSFER_EVAL = ProgressEvaluatorBuilder.newBuilder()
* .addStep("BankTransferRequest", "Transfer order accepted", 0.25)
* .composedBy(MoneyTransferCommand.class, 1)
* .addStep("WithdrawalOrder", "Withdrawal order accepted", 0.25)
* .composedBy(DisposeWithdrawalCommand.class, 1)
* .addStep("DepositOrder", "Deposit order accepted", 0.25)
* .composedBy(DisposeDepositCommand.class, 1)
* .addStep("Confirmation", "Orders confirmed", 0.25)
* .composedBy(ConfirmWithdrawalCommand.class, 1)
* .composedBy(ConfirmDepositCommand.class, 1)
* .build();}
* Builder instances can be reused - it is safe to call {@link #build}
* multiple times to build multiple instances in series.
*
* @author Domenico Maria Giffone.
* @since 1.2
*/
public class ProgressEvaluatorBuilder {
private ProgressEvaluatorBuilder() {
}
public static interface StepDefinition {
FirstCommandDefinition addStep(String stepName, double stepWeight);
FirstCommandDefinition addStep(String stepName, String stepDescription, double stepWeight);
}
public static interface FirstCommandDefinition {
NextCommandDefinition composedBy(Class expectedType, int expectedAmount);
}
public static interface NextCommandDefinition extends FirstCommandDefinition, StepDefinition {
ProgressEvaluator build();
}
public static StepDefinition newBuilder() {
return new StepBuilder();
}
private static final class StepBuilder implements StepDefinition, FirstCommandDefinition, NextCommandDefinition {
private static final double TOTAL_WEIGHT_INVARIANT = 1.00D;
private List steps = new ArrayList();
private BigDecimal stepsWeight = BigDecimal.ZERO;
private Step currentStep;
@Override
public ProgressEvaluator build() {
validate();
return new DefaultProgressEvaluator(steps);
}
private void validate() {
Contract.ENSURE.isTrue(TOTAL_WEIGHT_INVARIANT == stepsWeight.doubleValue(),
"The sum of steps weight must be equal to 1",
"Current weight is [{}]", stepsWeight.toPlainString());
Set intersections = newHashSet();
for (int i = 0; i < steps.size(); i++) {
Set reference = steps.get(i).getCommands();
for (int k = 0; k < steps.size(); k++) {
if (k != i) {
intersections.addAll(intersection(reference, steps.get(k).getCommands()));
}
}
}
Contract.ENSURE.isTrue(intersections.size() == 0,
"The same command can not belong to more than one step",
"Repeated commands found: [{}]", intersections);
}
@Override
public NextCommandDefinition composedBy(Class expectedType, int expectedAmount) {
currentStep.addCommand(expectedType, expectedAmount);
return this;
}
@Override
public FirstCommandDefinition addStep(String stepName, double stepWeight) {
return addStep(stepName, null, stepWeight);
}
@Override
public FirstCommandDefinition addStep(String stepName, String stepDescription, double stepWeight) {
currentStep = new Step(stepName, stepDescription, stepWeight);
steps.add(currentStep);
stepsWeight = stepsWeight.add(BigDecimal.valueOf(stepWeight)).setScale(2, ROUND_HALF_UP);
return this;
}
}
}