class PasswordEncoderPlugin implements IPlugin {

    @Override
    public void load() throws PluginException {

        try {
            IBootstrapItem<String> item = new BootstrapItem("PasswordEncoderPlugin");
            item
                .process(() -> {
                    try {
                        IOC.register(Keys.getOrAdd("CharSequenceCodec"), new ApplyFunctionToArgumentsStrategy(
                                (args) -> {
                                    try {
                                        String charset = String.valueOf(args[0]);
                                        return CharSequenceCodec.create(charset);
                                    } catch (Exception e) {
                                        throw new RuntimeException("Error during resolving char sequence codec", e);
                                    }
                                }
                            )
                        );
                        IOC.register(Keys.getOrAdd("Base64Encoder"), new ApplyFunctionToArgumentsStrategy(
                                (args) -> {
                                    try {
                                        return Base64.create();
                                    } catch (Exception e) {
                                        throw new RuntimeException("Error during resolving encoder", e);
                                    }
                                }
                            )
                        );
                        IOC.register(Keys.getOrAdd("HexEncoder"), new ApplyFunctionToArgumentsStrategy(
                                (args) -> {
                                    try {
                                        return Hex.create();
                                    } catch (Exception e) {
                                        throw new RuntimeException("Error during resolving encoder", e);
                                    }
                                }
                            )
                        );
                        IOC.register(Keys.getOrAdd("PasswordEncoder"), new ApplyFunctionToArgumentsStrategy(
                                (args) -> {
                                    try {
                                        String algorithm = String.valueOf(args[0]);
                                        String encoderType = String.valueOf(args[1]);
                                        String charset = String.valueOf(args[2]);

                                        IEncoder encoder = IOC.resolve(Keys.getOrAdd(encoderType));
                                        ICharSequenceCodec charSequenceCodec = IOC.resolve(Keys.getOrAdd("CharSequenceCodec"), charset);
                                        return MDPasswordEncoder.create(algorithm, encoder, charSequenceCodec);
                                    } catch (Exception e) {
                                        throw new RuntimeException("Error during resolving password encoder", e);
                                    }
                                }
                            )
                        );
                    } catch (ResolutionException e) {
                        throw new ActionExecuteException("PasswordEncoder plugin can't load: can't get key");
                    } catch (InvalidArgumentException e) {
                        throw new ActionExecuteException("PasswordEncoder plugin can't load: can't create strategy");
                    } catch (RegistrationException e) {
                        throw new ActionExecuteException("PasswordEncoder plugin can't load: can't register new strategy");
                    }
                });
            bootstrap.add(item);
        } catch (InvalidArgumentException e) {
            throw new PluginException("Can't get BootstrapItem", e);
        }
    }

    public  PasswordEncoderPlugin(final IBootstrap<IBootstrapItem<String>> bootstrap);

}