class TokenCertificateService {

    public GeneratedCertRequestInfo generateCertRequest(String keyId, ClientId memberId, KeyUsageInfo keyUsage,
            String caName, Map<String, String> subjectFieldValues, CertificateRequestFormat format)
            throws CertificateAuthorityNotFoundException, ClientNotFoundException,
            WrongKeyUsageException,
            KeyNotFoundException,
            DnFieldHelper.InvalidDnParameterException, ActionNotPossibleException {

        // validate key and memberId existence
        TokenInfo tokenInfo = tokenService.getTokenForKeyId(keyId);
        auditDataHelper.put(tokenInfo);
        KeyInfo key = keyService.getKey(tokenInfo, keyId);
        auditDataHelper.put(key);
        auditDataHelper.put(KEY_USAGE, keyUsage);
        auditDataHelper.put(memberId);

        if (keyUsage == KeyUsageInfo.SIGNING) {
            // validate that the member exists or has a subsystem on this server
            if (!clientService.getLocalClientMemberIds().contains(memberId)) {
                throw new ClientNotFoundException("client with id " + memberId + ", or subsystem for it, " + NOT_FOUND);
            }
        }

        // check that keyUsage is allowed
        if (key.getUsage() != null) {
            if (key.getUsage() != keyUsage) {
                throw new WrongKeyUsageException();
            }
        }

        // validate that generate csr is possible
        if (keyUsage == KeyUsageInfo.SIGNING) {
            possibleActionsRuleEngine.requirePossibleKeyAction(PossibleActionEnum.GENERATE_SIGN_CSR,
                    tokenInfo, key);
        } else {
            possibleActionsRuleEngine.requirePossibleKeyAction(PossibleActionEnum.GENERATE_AUTH_CSR,
                    tokenInfo, key);
        }

        CertificateProfileInfo profile = null;
        try {
            profile = certificateAuthorityService.getCertificateProfile(caName, keyUsage, memberId, false);
        } catch (CertificateProfileInstantiationException e) {
            throw new DeviationAwareRuntimeException(e, e.getErrorDeviation());
        }

        List<DnFieldValue> dnFieldValues = dnFieldHelper.processDnParameters(profile, subjectFieldValues);

        String subjectName = dnFieldHelper.createSubjectName(dnFieldValues);
        auditDataHelper.put(SUBJECT_NAME, subjectName);
        auditDataHelper.put(CERTIFICATION_SERVICE_NAME, caName);
        auditDataHelper.put(CSR_FORMAT, format);

        try {
            return signerProxyFacade.generateCertRequest(keyId, memberId,
                    keyUsage, subjectName, format);
        } catch (CodedException e) {
            throw e;
        } catch (Exception e) {
            throw new SignerNotReachableException("Generate cert request failed", e);
        }
    }

    @Autowired @SuppressWarnings("checkstyle:ParameterNumber") public  TokenCertificateService(SignerProxyFacade signerProxyFacade, ClientService clientService,
            CertificateAuthorityService certificateAuthorityService, KeyService keyService, DnFieldHelper dnFieldHelper,
            GlobalConfService globalConfService, GlobalConfFacade globalConfFacade, ClientRepository clientRepository,
            ManagementRequestSenderService managementRequestSenderService, ServerConfService serverConfService,
            PossibleActionsRuleEngine possibleActionsRuleEngine, TokenService tokenService,
            SecurityHelper securityHelper, AuditDataHelper auditDataHelper,
            AuditEventHelper auditEventHelper);

}