Wstęp
Sekcja hook'ów
Jest to interfejs zawierający hook'i dla danej sekcji systemu. Sekcją taką mogą być zastępstwa użytkownika. Tworzony jest jeden interfejs SubstitutionHook, który zawiera zbiór metod (hook'ów) związanych z zastępstwami.
Należy pamiętać, aby po dodaniu nowej sekcji hook'ów uzupełnić listę z hook'ami w Spis hook'ów systemowych.
Definiowanie sekcji hook'ów składa się z 4 etapów.
Utworzenie interfejsu dla sekcji hook'ów
Każda sakcja hook'ów musi posiadać interfejs. Interfejs definiuje metody (hook'i), które mogą być zaimplementowane i wywoływane w systemie.
public interface SubstitutionHook { public boolean confirmCreateSubstitution( String userName, Substitution substitution ); public void substitutionAdded( String userName, Substitution substitution ); }
Interfejs SubstitutionHook definiuje dwa hook'i. Pierwszy jest wywoływany przed utworzeniem zastępstwa, w zależności jaka wartość będzie zwrócona, od tego będzie zależeć, czy zastępstwo powinno zostać utworzone. Drugi hook wywoływany jest już po pomyślnym dodaniu zastępstwa.
Interfejs musi znaleźć się w projekcie API.
Utworzenie klasy abstrakcyjnej dla sekcji hook'ów, która pełni rolę adaptera interfejsu
Klasa abstrakcyjna musi implementować utworzony interfejs oraz implementować wszystkie jego metody. Pełni ona rolę adaptera dla interfejsu. Dzięki temu we wdrożeniu nie trzeba implementować wszystkich metod, tylko te, które są potrzebne. Zapobiega to również błędom kompilacji we wdrożeniach w momencie, gdy zostanie dodany kolejny hook do interfejsu.
Uwaga
Implementowane metody nie mogą w żaden sposób zmieniać działania systemu. Powinny zachowywać się tak, jakby nie były w ogóle wykonywane. Logika metod powinna być zawarta we właściwej implementacji sekcji hook'ów.
Klasa abstrakcyjna powinna również implementować interfejs org.springframework.core.Ordered oraz jego metodę getOrder(). Klasa ta pozwala na wywołanie kilku hook'ów tego samego typu w określonej kolejności. Domyślnie implementowana metoda powinna zwracać wartość zapisaną w zmiennej Ordered.LOWEST_PRECEDENCE, co skutkuje tym, że taki hook wykonywany jest na samym końcu.
public abstract class SubstitutionHookAdapter implements SubstitutionHook, Ordered { public boolean confirmCreateSubstitution( String userName, Substitution substitution ) { return true; } public void substitutionAdded( String userName, Substitution substitution ) { } public int getOrder() { return Ordered.LOWEST_PRECEDENCE; } }
Adapter musi znaleźć się w projekcie API.
Utworzenie procesora dla sekcji hook'ów
Procesor musi implementować interfejs odpowiadający odpowiedniej sekcji hook'ów oraz rozszerzać klasę abstrakcyjną com.suncode.pwfl.hook.AbstractHookProcessor<T>, gdzie T - jest to typ odpowiedniej sekcji hook'ów. Dodatkowo procesor musi posiadać adnotację @HookType( value = clazz), gdzie clazz - jest to interfejs dla odpowiedniej sekcji hook'ów. Dzięki klasie AbstractHookProcessor procesor dziedziczy metodę getHooks(), która zwraca wszystkie zdefiniowane hook'i danego typu. Hooki te są rejestrowane podczas startu systemu za pomocą rejestratora HookRegistry.class.
@HookType( value = SubstitutionHook.class ) public class SubstitutionHookProcessor extends AbstractHookProcessor<SubstitutionHook> implements SubstitutionHook { public boolean confirmCreateSubstitution( String userName, Substitution substitution ) { boolean confirm = true; for ( SubstitutionHook hook : getHooks() ) { try { confirm = hook.confirmCreateSubstitution( String userName, substitution ); if( confirm == false ) { return false; } } catch ( Exception e ) { throw new HookExecutorException( "Hook " + hook.getClass().getSimpleName() + " zwrócił następujący wyjątek: '" + e.getMessage() + "'" ); } } return confirm; } public void substitutionAdded( final String userName, final Substitution substitution ) { everyHooks( new HookCallback<SubstitutionHook>() { @Override public void doWithHook( SubstitutionHook hook ) { hook.substitutionAdded( userName, substitution ); } } ); } }
Procesor powinien znaleźć się w projekcie CORE.
Osadzanie hook'ów w systemie
Po wykonaniu wszystkich wcześniejszych kroków, należy osadzić hook'i w odpowiednich miejscach systemu. Aby tego dokonać należy pobrać istniejąca instancję HookRegistry z contextu Spring'a.
@Autowired private HookRegistry hr;
lub
private HookRegistry hr = SpringContext.getBean( HookRegistry.class );
Mając instancję HookRegistry osadzamy hook'i następująco:
//dla hook'a confirmCreateSubstitution boolean confirm = hr.invoke( SubstitutionHook.class ).confirmCreateSubstitution( userName, substitution ); //dla hook'a substitutionAdded hr.invoke( SubstitutionHook.class ).substitutionAdded( userName, substitution );
Metoda invoke( SubstitutionHook.class ) zwraca procesor zarejestrowany dla sekcji hook'ów SubstitutionHook. Następnie w procesorze wywoływana jest odpowiednia metoda dla hook'a. Jeżeli nie ma utworzonej żadnej implementacji hook'a, to procesor niczego nie wykona.