@Nonnull
    @Override
    public Optional<? extends Algorithm> parse(
            @Nullable final String str, @Nonnull DetectionLocation detectionLocation) {
        if (str == null) {
            return Optional.empty();
        }

        String algorithmStr;
        Optional<Mode> modeOptional = Optional.empty();
        Optional<? extends Padding> paddingOptional = Optional.empty();
        if (str.contains("/")) {
            int slashIndex = str.indexOf("/");
            algorithmStr = str.substring(0, slashIndex);

            String rest = str.substring(slashIndex + 1);
            if (rest.contains("/")) {
                slashIndex = rest.indexOf("/");
                // mode
                final String modeStr = rest.substring(0, slashIndex);
                final JcaModeMapper jcaModeMapper = new JcaModeMapper();
                modeOptional = jcaModeMapper.parse(modeStr, detectionLocation);
                // padding
                String paddingStr = rest.substring(slashIndex + 1);
                final JcaPaddingMapper jcaPaddingMapper = new JcaPaddingMapper();
                paddingOptional = jcaPaddingMapper.parse(paddingStr, detectionLocation);
            }
        } else {
            algorithmStr = str;
        }

        // check if it is pbe
        JcaPasswordBasedEncryptionMapper pbeMapper = new JcaPasswordBasedEncryptionMapper();
        Optional<PasswordBasedEncryption> pbeOptional =
                pbeMapper.parse(algorithmStr, detectionLocation);
        if (pbeOptional.isPresent()) {
            // pbe
            return pbeOptional;
        }

        Optional<? extends Algorithm> possibleCipher = map(algorithmStr, detectionLocation);
        if (possibleCipher.isEmpty()) {
            return Optional.empty();
        }
        final Algorithm algorithm = possibleCipher.get();

        modeOptional.ifPresent(algorithm::put);
        paddingOptional.ifPresent(algorithm::put);
        return Optional.of(algorithm);
    }
@Test
    void pbe() {
        DetectionLocation testDetectionLocation =
                new DetectionLocation("testfile", 1, 1, List.of("test"), () -> "SSL");

        JcaCipherMapper jcaCipherMapper = new JcaCipherMapper();
        Optional<? extends Algorithm> cipherOptional =
                jcaCipherMapper.parse("PBEWithMD5AndDES", testDetectionLocation);

        assertThat(cipherOptional).isPresent();
        assertThat(cipherOptional.get().is(PasswordBasedEncryption.class)).isTrue();
        PasswordBasedEncryption pbe = (PasswordBasedEncryption) cipherOptional.get();

        assertThat(pbe.getName()).isEqualTo("PBEWithMD5AndDES");
        assertThat(pbe.hasChildren()).isTrue();
        assertThat(pbe.getChildren().values()).hasSize(2);

        assertThat(pbe.getDigest()).isPresent();

        MessageDigest digest = pbe.getDigest().get();
        assertThat(digest).isInstanceOf(MD5.class);
        assertThat(digest.getDigestSize()).isPresent();
        assertThat(digest.getDigestSize().get().getValue()).isEqualTo(128);
        assertThat(digest.getBlockSize()).isPresent();
        assertThat(digest.getBlockSize().get().getValue()).isEqualTo(512);

        assertThat(pbe.getCipher()).isPresent();
        IPrimitive encryptionAlgorithm = pbe.getCipher().get();
        assertThat(encryptionAlgorithm).isInstanceOf(DES.class);
    }