class HardMediumSoftLongScoreHolderImpl extends AbstractScoreHolder<HardMediumSoftLongScore>
        implements HardMediumSoftLongScoreHolder {

    protected final Map<Rule, LongMatchExecutor> matchExecutorByNumberMap = new LinkedHashMap<>();
    /** Slower than {@link #matchExecutorByNumberMap} */
    protected final Map<Rule, ScoreMatchExecutor<HardMediumSoftLongScore>> matchExecutorByScoreMap = new LinkedHashMap<>();

    protected long hardScore;
    protected long mediumScore;
    protected long softScore;

    public HardMediumSoftLongScoreHolderImpl(boolean constraintMatchEnabled) {
        super(constraintMatchEnabled);
    }

    public long getHardScore() {
        return hardScore;
    }

    public long getMediumScore() {
        return mediumScore;
    }

    public long getSoftScore() {
        return softScore;
    }

    // ************************************************************************
    // Setup methods
    // ************************************************************************

    @Override
    public void configureConstraintWeight(Rule rule, HardMediumSoftLongScore constraintWeight) {
        super.configureConstraintWeight(rule, constraintWeight);
        LongMatchExecutor matchExecutor;
        if (constraintWeight.isZero()) {
            matchExecutor = (RuleContext kcontext, long matchWeight) -> {
            };
        } else if (constraintWeight.mediumScore() == 0 && constraintWeight.softScore() == 0) {
            matchExecutor =
                    (RuleContext kcontext, long matchWeight) -> addHardConstraintMatch(kcontext,
                            constraintWeight.hardScore() * matchWeight);
        } else if (constraintWeight.hardScore() == 0 && constraintWeight.softScore() == 0) {
            matchExecutor =
                    (RuleContext kcontext, long matchWeight) -> addMediumConstraintMatch(kcontext,
                            constraintWeight.mediumScore() * matchWeight);
        } else if (constraintWeight.hardScore() == 0 && constraintWeight.mediumScore() == 0) {
            matchExecutor =
                    (RuleContext kcontext, long matchWeight) -> addSoftConstraintMatch(kcontext,
                            constraintWeight.softScore() * matchWeight);
        } else {
            matchExecutor =
                    (RuleContext kcontext, long matchWeight) -> addMultiConstraintMatch(kcontext,
                            constraintWeight.hardScore() * matchWeight, constraintWeight.mediumScore() * matchWeight,
                            constraintWeight.softScore() * matchWeight);
        }
        matchExecutorByNumberMap.put(rule, matchExecutor);
        matchExecutorByScoreMap.put(rule, (RuleContext kcontext,
                HardMediumSoftLongScore weightMultiplier) -> addMultiConstraintMatch(kcontext,
                        constraintWeight.hardScore() * weightMultiplier.hardScore(),
                        constraintWeight.mediumScore() * weightMultiplier.mediumScore(),
                        constraintWeight.softScore() * weightMultiplier.softScore()));
    }

    // ************************************************************************
    // Penalize and reward methods
    // ************************************************************************

    @Override
    public void penalize(RuleContext kcontext) {
        impactScore(kcontext, -1L);
    }

    @Override
    public void penalize(RuleContext kcontext, long weightMultiplier) {
        impactScore(kcontext, -weightMultiplier);
    }

    @Override
    public void penalize(RuleContext kcontext, long hardWeightMultiplier, long mediumWeightMultiplier,
            long softWeightMultiplier) {
        impactScore(kcontext, -hardWeightMultiplier, -mediumWeightMultiplier, -softWeightMultiplier);
    }

    @Override
    public void reward(RuleContext kcontext) {
        impactScore(kcontext, 1L);
    }

    @Override
    public void reward(RuleContext kcontext, long weightMultiplier) {
        impactScore(kcontext, weightMultiplier);
    }

    @Override
    public void reward(RuleContext kcontext, long hardWeightMultiplier, long mediumWeightMultiplier,
            long softWeightMultiplier) {
        impactScore(kcontext, hardWeightMultiplier, mediumWeightMultiplier, softWeightMultiplier);
    }

    @Override
    public void impactScore(RuleContext kcontext) {
        impactScore(kcontext, 1L);
    }

    @Override
    public void impactScore(RuleContext kcontext, int weightMultiplier) {
        impactScore(kcontext, (long) weightMultiplier);
    }

    @Override
    public void impactScore(RuleContext kcontext, long weightMultiplier) {
        Rule rule = kcontext.getRule();
        LongMatchExecutor matchExecutor = matchExecutorByNumberMap.get(rule);
        if (matchExecutor == null) {
            throw new IllegalStateException("The DRL rule (" + rule.getPackageName() + ":" + rule.getName()
                    + ") does not match a @" + ConstraintWeight.class.getSimpleName() + " on the @"
                    + ConstraintConfiguration.class.getSimpleName() + " annotated class.");
        }
        matchExecutor.accept(kcontext, weightMultiplier);
    }

    @Override
    public void impactScore(RuleContext kcontext, BigDecimal weightMultiplier) {
        throw new UnsupportedOperationException("In the rule (" + kcontext.getRule().getName()
                + "), the scoreHolder class (" + getClass()
                + ") does not support a BigDecimal weightMultiplier (" + weightMultiplier + ").\n"
                + "If you're using constraint streams, maybe switch from penalizeBigDecimal() to penalizeLong().");
    }

    private void impactScore(RuleContext kcontext, long hardWeightMultiplier, long mediumWeightMultiplier,
            long softWeightMultiplier) {<FILL_FUNCTION_BODY>}

    // ************************************************************************
    // Other match methods
    // ************************************************************************

    @Override
    public void addHardConstraintMatch(RuleContext kcontext, long hardWeight) {
        hardScore += hardWeight;
        registerConstraintMatch(kcontext, () -> hardScore -= hardWeight, () -> HardMediumSoftLongScore.ofHard(hardWeight));
    }

    @Override
    public void addMediumConstraintMatch(RuleContext kcontext, long mediumWeight) {
        mediumScore += mediumWeight;
        registerConstraintMatch(kcontext, () -> mediumScore -= mediumWeight,
                () -> HardMediumSoftLongScore.ofMedium(mediumWeight));
    }

    @Override
    public void addSoftConstraintMatch(RuleContext kcontext, long softWeight) {
        softScore += softWeight;
        registerConstraintMatch(kcontext, () -> softScore -= softWeight, () -> HardMediumSoftLongScore.ofSoft(softWeight));
    }

    @Override
    public void addMultiConstraintMatch(RuleContext kcontext, long hardWeight, long mediumWeight, long softWeight) {
        hardScore += hardWeight;
        mediumScore += mediumWeight;
        softScore += softWeight;
        registerConstraintMatch(kcontext,
                () -> {
                    hardScore -= hardWeight;
                    mediumScore -= mediumWeight;
                    softScore -= softWeight;
                },
                () -> HardMediumSoftLongScore.of(hardWeight, mediumWeight, softWeight));
    }

    @Override
    public HardMediumSoftLongScore extractScore(int initScore) {
        return HardMediumSoftLongScore.ofUninitialized(initScore, hardScore, mediumScore, softScore);
    }

}

        Rule rule = kcontext.getRule();
        ScoreMatchExecutor<HardMediumSoftLongScore> matchExecutor = matchExecutorByScoreMap.get(rule);
        if (matchExecutor == null) {
            throw new IllegalStateException("The DRL rule (" + rule.getPackageName() + ":" + rule.getName()
                    + ") does not match a @" + ConstraintWeight.class.getSimpleName() + " on the @"
                    + ConstraintConfiguration.class.getSimpleName() + " annotated class.");
        }
        matchExecutor.accept(kcontext,
                HardMediumSoftLongScore.of(hardWeightMultiplier, mediumWeightMultiplier, softWeightMultiplier));
    
<methods>public static ScoreHolder_ buildScoreHolder(ScoreDefinition<Score_>, boolean) ,public void configureConstraintWeight(Rule, org.optaplanner.core.api.score.buildin.hardmediumsoftlong.HardMediumSoftLongScore) ,public abstract org.optaplanner.core.api.score.buildin.hardmediumsoftlong.HardMediumSoftLongScore extractScore(int) ,public Map<java.lang.String,ConstraintMatchTotal<org.optaplanner.core.api.score.buildin.hardmediumsoftlong.HardMediumSoftLongScore>> getConstraintMatchTotalMap() ,public Map<java.lang.Object,Indictment<org.optaplanner.core.api.score.buildin.hardmediumsoftlong.HardMediumSoftLongScore>> getIndictmentMap() ,public void impactScore(RuleContext) ,public abstract void impactScore(RuleContext, int) ,public abstract void impactScore(RuleContext, long) ,public abstract void impactScore(RuleContext, java.math.BigDecimal) ,public boolean isConstraintMatchEnabled() <variables>private static final java.lang.String CUSTOM_SCORE_HOLDER_CLASS_PROPERTY_NAME,protected final non-sealed boolean constraintMatchEnabled,protected final non-sealed Map<java.lang.String,ConstraintMatchTotal<org.optaplanner.core.api.score.buildin.hardmediumsoftlong.HardMediumSoftLongScore>> constraintMatchTotalMap,protected final non-sealed Map<java.lang.Object,Indictment<org.optaplanner.core.api.score.buildin.hardmediumsoftlong.HardMediumSoftLongScore>> indictmentMap