class SAML2JdbcMetadataGenerator extends BaseSAML2MetadataGenerator {
    private String tableName = "sp_metadata";

    private final JdbcTemplate template;

    private final String entityId;

    /** {@inheritDoc} */
    @Override
    @SuppressWarnings("PMD.NP_NULL_ON_SOME_PATH_FROM_RETURN_VALUE")
    public AbstractMetadataResolver createMetadataResolver() throws Exception {
        var metadata = fetchMetadata();
        try (var is = new ByteArrayInputStream(metadata)) {
            var document = Configuration.getParserPool().parse(is);
            var root = document.getDocumentElement();
            return new DOMMetadataResolver(root);
        }
    }

    /** {@inheritDoc} */
    @Override
    public boolean storeMetadata(final String metadata, final boolean force) {<FILL_FUNCTION_BODY>}

    /**
     * <p>updateMetadata.</p>
     *
     * @param metadataToUse a {@link String} object
     * @return a boolean
     */
    protected boolean updateMetadata(final String metadataToUse) {
        var updateSql = String.format("UPDATE %s SET metadata='%s' WHERE entityId='%s'", this.tableName,
            encodeMetadata(metadataToUse), this.entityId);
        var count = template.update(updateSql);
        return count > 0;
    }

    /**
     * <p>insertMetadata.</p>
     *
     * @param metadataToUse a {@link String} object
     * @return a boolean
     */
    protected boolean insertMetadata(String metadataToUse) {
        var insert = new SimpleJdbcInsert(this.template)
            .withTableName(String.format("%s", this.tableName))
            .usingColumns("entityId", "metadata");
        Map<String, Object> parameters = new HashMap<>();
        parameters.put("entityId", this.entityId);
        parameters.put("metadata", encodeMetadata(metadataToUse));
        return insert.execute(parameters) > 0;
    }

    /**
     * <p>fetchMetadata.</p>
     *
     * @return an array of {@link byte} objects
     */
    protected byte[] fetchMetadata() {
        var sql = String.format("SELECT metadata FROM %s WHERE entityId='%s'", this.tableName, this.entityId);
        return decodeMetadata(template.queryForObject(sql, String.class));
    }

    /**
     * <p>decodeMetadata.</p>
     *
     * @param metadata a {@link String} object
     * @return an array of {@link byte} objects
     */
    protected byte[] decodeMetadata(final String metadata) {
        return Base64.getDecoder().decode(metadata);
    }

    /**
     * <p>encodeMetadata.</p>
     *
     * @param metadataToUse a {@link String} object
     * @return a {@link String} object
     */
    protected String encodeMetadata(String metadataToUse) {
        return Base64.getEncoder().encodeToString(metadataToUse.getBytes(StandardCharsets.UTF_8));
    }
}

        if (CommonHelper.isBlank(metadata)) {
            logger.info("No metadata is provided");
            return false;
        }

        var metadataToUse = isSignMetadata() ? getMetadataSigner().sign(metadata) : metadata;
        CommonHelper.assertNotBlank("metadata", metadataToUse);

        var metadataEntityId = Configuration.deserializeSamlObject(metadataToUse)
            .map(EntityDescriptor.class::cast)
            .map(EntityDescriptor::getEntityID)
            .orElseThrow();
        if (!metadataEntityId.equals(this.entityId)) {
            throw new SAMLException("Entity id from metadata " + metadataEntityId
                + " does not match supplied entity id " + this.entityId);
        }

        try {
            var sql = String.format("SELECT entityId FROM %s WHERE entityId='%s'", this.tableName, this.entityId);
            var entityId = template.queryForObject(sql, String.class);
            logger.debug("Updating metadata entity [{}]", entityId);
            return updateMetadata(metadataToUse);
        } catch (final EmptyResultDataAccessException e) {
            return insertMetadata(metadataToUse);
        }
    
<methods>public non-sealed void <init>() ,public org.opensaml.saml.saml2.metadata.EntityDescriptor buildEntityDescriptor() ,public org.opensaml.saml.metadata.resolver.MetadataResolver buildMetadataResolver() throws java.lang.Exception,public List<java.lang.String> getBlackListedSignatureSigningAlgorithms() ,public java.lang.String getMetadata(org.opensaml.saml.saml2.metadata.EntityDescriptor) throws java.lang.Exception,public List<java.lang.String> getSignatureAlgorithms() ,public List<java.lang.String> getSignatureReferenceDigestMethods() <variables>protected java.lang.String assertionConsumerServiceUrl,protected boolean authnRequestSigned,protected List<java.lang.String> blackListedSignatureSigningAlgorithms,protected final org.opensaml.core.xml.XMLObjectBuilderFactory builderFactory,private List<org.pac4j.saml.metadata.SAML2MetadataContactPerson> contactPersons,protected org.pac4j.saml.crypto.CredentialProvider credentialProvider,protected int defaultACSIndex,protected org.opensaml.xmlsec.SignatureSigningConfiguration defaultSignatureSigningConfiguration,protected java.lang.String entityId,protected final org.opensaml.xmlsec.algorithm.AlgorithmRegistry globalAlgorithmRegistry,protected final org.slf4j.Logger logger,protected final org.opensaml.core.xml.io.MarshallerFactory marshallerFactory,private org.pac4j.saml.metadata.SAML2MetadataSigner metadataSigner,private List<org.pac4j.saml.metadata.SAML2MetadataUIInfo> metadataUIInfos,protected java.lang.String nameIdPolicyFormat,protected java.lang.String requestInitiatorLocation,protected List<org.pac4j.saml.metadata.SAML2ServiceProviderRequestedAttribute> requestedAttributes,protected java.lang.String responseBindingType,protected boolean signMetadata,protected List<java.lang.String> signatureAlgorithms,protected List<java.lang.String> signatureReferenceDigestMethods,protected java.lang.String singleLogoutServiceUrl,private List<java.lang.String> supportedProtocols,protected boolean wantAssertionSigned