2013-10-14 6 views
9

Quanto segue è un'approssimazione del problema che sto affrontando.Guice: Come modificare l'iniezione su runtime basato su una (proprietà web dinamica)

Pensa di avere un validatore di password con alcune regole.

public interface RuleChecker{ 

    //Checks for a password strenght, returns 10 
    //for strong or 0 for soft password. 
    int check(String pass); 
} 

E quindi abbiamo diverse implementazioni, il nostro servizio accetterà solo la password se è superiore a 8 punti.

public class NoCheck implements RuleChecker { 
    public int check(String pass){return 10;} 
} 

public class LengthCheck implements RuleChecker{ 
    ... 
} 
public class AlphanumericCheck implements RuleChecker{ 
    ... 
} 
public class AlphaAndLenghtCheckAdapter implements RuleChecker{ 
    ... 
} 

Ma a scopo di test, vogliamo implementare un webservice all'interno dell'applicazione in cui possiamo "admin" quelle regole, e selezionare quelli da avere.

public class PasswordCheckService{ 

    private RuleChecker checker; 

    @Inject 
    public PasswordCheckService(final RuleChecker checker){ 
     this.checker = checker; 
    } 

    public boolean checkPassword(String password){ 
     return checker.check(password) > 8; 
    } 
} 

Quindi, c'è un modo in Guice, di cambiare in fase di esecuzione, l'iniezione di un servizio ha?

Esempio:

Abbiamo iniziato l'applicazione e per impostazione predefinita LengthCheck viene selezionato e iniettato sulla domanda, sul sito selezioniamo la casella di controllo NOCHECK e salvare le opzioni, che è memorizzato nel database, posso configurare Guice a cambia automaticamente il bean che il servizio aveva iniettato in precedenza? quindi da ora in poi non ci saranno controlli sulle nuove password?

-

Per il momento, ho trovato questi argomenti

Google Guice and varying injections at runtime ma non so se questo tipo di fornitori si inserisce il mio problema.

Guice runtime dependency parameters reinjection Quella bella domanda sta parlando di qualcosa di simile, ma non quello che sto cercando forma.

guice: runtime injection/binding at command line Questo è il più vicino al mio problema ma lo fa solo all'avvio di "runtime" e non lo modifica nel tempo.

Qualsiasi aiuto?

Grazie!

Utilizzo del suggerimento del primo commento Ho implementato questo POC ma ancora non funziona, se si cambia selezionare un altro pulsante il bean di servizio non viene aggiornato. https://bitbucket.org/ramonboza/guicedynamicconfig

+0

Bella domanda. Ho cercato di fare qualcosa di molto simile. – tom

risposta

4

Creare un provider per ogni tipo di campo (login, password, data di nascita ...), con un parametro per modificare l'implementazione da restituire.

public class MyModule extends AbstractModule { 

    public void configure() { 
     bind(RuleChecker.class).annotatedWith(named("password")).toProvider(PasswordRuleCheckerProvider.class); 
     bind(RuleChecker.class).annotatedWith(named("login")).toProvider(LoginRuleCheckerProvider.class); 
    } 
} 

public static class PasswordRuleCheckerProvider implements Provider<RuleChecker> { 

    private static CheckType type = CheckType.ALPHANUMERIC; 
    // static type setter. 

    public RuleChecker get() { 
     // it would even be better if you could use singletons here. 
     switch(type) { 
      case LENGTH: 
       return new LengthCheck(); 
      case ALPHANUMERIC: 
       return new AlphanumericCheck(); 
      case ALPHALENGTH: 
       return new AlphaAndLenghtCheckAdapter(); 
      case NONE: 
      default: 
       return NoCheck(); 
     } 
    } 
} 
// Almost same provider for your LoginRuleCheckerProvider. You could do something generic. 

Nella sezione di amministrazione si modifica il valore "tipo", quindi le regole cambieranno. Può influenzare un insieme limitato di campi, grazie alle annotazioni. Ad esempio: PasswordRuleCheckerProvider.setType(CheckType.LENGTH);. Interverrà solo sui campi con @Named('password').

si deve dichiarare i vostri campi e servizi come questo:

public abstract class DynamicService { 
    protected void updateService() { 
     // Reinject with the new implementations the members. 
     App.getInjector().injectMembers(this); 
    } 
} 

public class PasswordCheckService extends DynamicService { 
    @Inject 
    @Named("password") 
    private RuleChecker passwordChecker; 

    public void changePasswordCheckType(CheckType type) { 
     PasswordRuleCheckerProvider.setType(type); 
     // Reinject, so you have your new implementation. 
     updateService(); 
    } 

    // [...] 
} 
+0

Sono gonnna do a PoC per provare la tua approssimazione;), spero di tornare tra un paio d'ore (ora di pranzo xD) – RamonBoza

+0

Argomento aggiornato, implementato il POC senza fortuna, controlla https://bitbucket.org/ramonboza/guicedynamicconfig – RamonBoza

+0

Gestito per farlo funzionare localmente. Ho aggiornato il post. Devi solo ricaricare le dipendenze e mantenere il campo 'tipo' statico nel tuo provider. –