@Override
    public void initSession(T param) throws ExtensionException {
        // remove session before init
        session.remove();

        IBusiness<T> matchedBusiness = null;
        List<String> matchedBusinessCodes = new ArrayList<>();
        for (IBusiness<T> business : businessManager.listAllBusinesses()) {
            if (business.match(param)) {
                if (matchedBusiness == null) {
                    matchedBusiness = business; // first matched
                }
                matchedBusinessCodes.add(business.code());
            }
        }

        if (matchBusinessStrict) {
            if (matchedBusiness == null) {
                throw new ExtensionException("business not found");
            }
            if (matchedBusinessCodes.size() > 1) {
                throw new ExtensionException("multiple business found, matched business codes: [" + String.join(", ", matchedBusinessCodes) + "]");
            }
        }

        if (matchedBusiness != null) {
            if (enableLogger) {
                logger.info("[ExtensionFactory] init session match business: " + matchedBusiness.code() + " priority: " + matchedBusiness.priority());
            }

            session.setMatchedCode(matchedBusiness.code(), matchedBusiness.priority());
            for (UsedAbility usedAbility : matchedBusiness.usedAbilities()) {
                IAbility<T> ability = abilityManager.getAbility(usedAbility.code());
                if (ability == null) {
                    throw new ExtensionException("business " + matchedBusiness.code() + " used ability " + usedAbility.code() + " not found");
                }
                if (ability.match(param)) {
                    if (enableLogger) {
                        logger.info("[ExtensionFactory] init session match ability: " + usedAbility.code() + " priority: " + usedAbility.priority());
                    }
                    session.setMatchedCode(usedAbility.code(), usedAbility.priority());
                }
            }
        }

        IAbility<T> defaultAbility = abilityManager.getAbility(BaseDefaultAbility.DEFAULT_CODE);

        session.setMatchedCode(defaultAbility.code(), defaultAbilityPriority);
        if (enableLogger) {
            logger.info("[ExtensionFactory] init session match default ability: " + defaultAbility.code() + " priority: " + defaultAbilityPriority);
        }
    }
@Test
    public void testInitSession() throws Exception {
        ExtensionException e;
        DefaultExtContext<Object> context = new DefaultExtContext<>(false, true);

        context.registerBusiness(new BusinessX());
        context.registerBusiness(new BusinessY());
        context.registerBusiness(new BusinessZ());
        context.registerBusiness(new BusinessZZ());

        e = assertThrows(ExtensionException.class, () -> context.initSession("UnknownBiz"));
        assertEquals("business not found", e.getMessage());

        e = assertThrows(ExtensionException.class, () -> context.initSession("BusinessZZ"));
        assertEquals("multiple business found, matched business codes: [BusinessZ, BusinessZZ]", e.getMessage());

        e = assertThrows(ExtensionException.class, () -> context.initSession("BusinessX"));
        assertEquals("ability AbilityM not found", e.getMessage());

        context.registerAbility(new AbilityM());

        e = assertThrows(ExtensionException.class, () -> context.initSession("BusinessX"));
        assertEquals("ability ability.application.default not found", e.getMessage());

        context.registerAbility(new ExtDefaultAbility());

        context.initSession("BusinessX");

        context.validateContext();
    }