class DnFieldHelper {

    public List<DnFieldValue> processDnParameters(CertificateProfileInfo profile, Map<String, String> dnParameters)
            throws InvalidDnParameterException {
        Set<String> unprocessedParameters = new HashSet<>(dnParameters.keySet());
        List<DnFieldValue> dnValues = new ArrayList<>();
        // match all dn fields with either default values or actual parameters
        for (DnFieldDescription description: profile.getSubjectFields()) {
            String fieldValue = null;
            boolean parameterIsMissing = StringUtils.isBlank(dnParameters.get(description.getId()));
            if (description.isRequired() && (!description.isReadOnly()) && parameterIsMissing) {
                throw new InvalidDnParameterException("missing parameter: " + description.getId());
            }
            if (description.isReadOnly() || parameterIsMissing) {
                fieldValue = description.getDefaultValue();
            } else {
                fieldValue = dnParameters.get(description.getId());
            }
            dnValues.add(new DnFieldValueImpl(description.getId(), fieldValue));
            unprocessedParameters.remove(description.getId());
        }
        if (!unprocessedParameters.isEmpty()) {
            throw new InvalidDnParameterException("extraneous parameters: " + unprocessedParameters);
        }
        // validate
        for (DnFieldValue dnValue: dnValues) {
            try {
                profile.validateSubjectField(dnValue);
            } catch (Exception e) {
                throw new InvalidDnParameterException(e);
            }
        }
        return dnValues;
    }

}