class ActionListCustomizationMediatorImpl implements ActionListCustomizationMediator {

    @Override
    public Map<String, ActionItemCustomization> getActionListCustomizations(String principalId,
            List<ActionItem> actionItems) throws RiceIllegalArgumentException {
        if (StringUtils.isBlank(principalId)) {
            throw new RiceIllegalArgumentException("invalid principalId: " + principalId);
        }
        if (actionItems == null) {
            actionItems = Collections.emptyList();
        }

        // map from action item ID to ActionItemCustomization
        Map<String, ActionItemCustomization> results = new HashMap<String, ActionItemCustomization>();

        // group each action item by application id that needs to be called for action list customizations (note that
        // the application id comes from the extension/rule attribute record, most action lists will have doc types
        // with no custom action list attribute, though the default still needs to be run in this case)

        ListMultimap<String, ActionItem> itemsByApplicationId = ArrayListMultimap.create();

        for (ActionItem actionItem : actionItems) {
            //DocumentType docType = KewApiServiceLocator.getDocumentTypeService().getDocumentTypeByName(actionItem.getDocName());
            DocumentType docType = getDocumentTypeService().findByName(actionItem.getDocName());
            if (docType == null) {
                LOG.error(String.format("Action item %s has an invalid document type name of %s",
                        actionItem.getId(), actionItem.getDocName()));
                // OK to have a null key, this represents the default app id
                itemsByApplicationId.put(null, actionItem);
            } else {
                // OK to have a null key, this represents the default app id
                itemsByApplicationId.put(getActionListCustomizationApplicationId(docType), actionItem);
            }
        }

        // For each application id, pass all action items which might need to be customized (because they have a
        // document type, which declares an action list attribute, which has an application id declared) to the
        // appropriate ActionListCustomizationHandlerService endpoint

        for (String applicationId : itemsByApplicationId.keySet()) {
            ActionListCustomizationHandlerService actionListCustomizationHandler =
                    getActionListCustomizationHandlerServiceChooser().getByApplicationId(applicationId);

            if (actionListCustomizationHandler == null) {
                // get the local ActionListCustomizationHandlerService as a fallback
                actionListCustomizationHandler =
                        getActionListCustomizationHandlerServiceChooser().getByApplicationId(null);
            }

            List<ActionItemCustomization> customizations =
                    actionListCustomizationHandler.customizeActionList(principalId, itemsByApplicationId.get(
                            applicationId));


            // Get back the customized results and reassemble with customized results from all different application
            // customizations (as well as default customizations)
            if (customizations != null) for (ActionItemCustomization customization : customizations) {
                results.put(customization.getActionItemId(), customization);
            }
        }

        return results;
    }

}