class CertificateGenerator implements CredentialGenerator<CertificateCredentialValue> {

  @Override
  public CertificateCredentialValue generateCredential(final GenerationParameters p) {
    final CertificateGenerationParameters params = (CertificateGenerationParameters) p;
    final KeyPair keyPair;
    final String privatePem;
    try {
      keyPair = keyGenerator.generateKeyPair(params.getKeyLength());
      privatePem = CertificateFormatter.pemOf(keyPair.getPrivate());
    } catch (final Exception e) {
      throw new RuntimeException(e);
    }

    if (params.isSelfSigned()) {
      try {
        final String cert = CertificateFormatter.pemOf(signedCertificateGenerator.getSelfSigned(keyPair, params));
        return new CertificateCredentialValue(cert, cert, privatePem, null, params.isCa(), params.isSelfSigned(), true, false);
      } catch (final Exception e) {
        throw new RuntimeException(e);
      }
    } else {
      final String caName = params.getCaName();
      final CertificateCredentialValue latestNonTransitionalCaVersion = certificateAuthorityService.findActiveVersion(caName);
      if (latestNonTransitionalCaVersion.getPrivateKey() == null) {
        throw new ParameterizedValidationException(ErrorMessages.CA_MISSING_PRIVATE_KEY);
      }
      final CertificateCredentialValue transitionalCaVersion = certificateAuthorityService.findTransitionalVersion(caName);

      String signingCaCertificate;
      String signingCaPrivateKey;
      String trustedCaCertificate = null;

      if (shouldUseTransitionalParentToSign(params.getAllowTransitionalParentToSign(), latestNonTransitionalCaVersion, transitionalCaVersion)) {
        signingCaCertificate = transitionalCaVersion.getCertificate();
        signingCaPrivateKey = transitionalCaVersion.getPrivateKey();
        trustedCaCertificate = latestNonTransitionalCaVersion.getCertificate();
      } else {
        signingCaCertificate = latestNonTransitionalCaVersion.getCertificate();
        signingCaPrivateKey = latestNonTransitionalCaVersion.getPrivateKey();
        if (transitionalCaVersion != null) {
          trustedCaCertificate = transitionalCaVersion.getCertificate();
        }
      }

      try {

        final CertificateReader certificateReader = new CertificateReader(signingCaCertificate);

        final X509Certificate cert = signedCertificateGenerator.getSignedByIssuer(
          keyPair,
          params,
          certificateReader.getCertificate(),
          PrivateKeyReader.getPrivateKey(signingCaPrivateKey)
        );
        return new CertificateCredentialValue(signingCaCertificate, CertificateFormatter.pemOf(cert), privatePem, caName, trustedCaCertificate, params.isCa(), params.isSelfSigned(), true, false);
      } catch (final Exception e) {
        throw new RuntimeException(e);
      }
    }
  }

  @Autowired public  CertificateGenerator(
    final RsaKeyPairGenerator keyGenerator,
    final SignedCertificateGenerator signedCertificateGenerator,
    final CertificateAuthorityService certificateAuthorityService);

}