Skip to end of metadata
Go to start of metadata

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.

Przykład
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.

Przykład
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 odpowiada za wykonywanie wszystkich hook'ów tego samego typu w odpowiedniej kolejności. Dodatkowo musi on wyłapywać wyjątek HookException, który może być rzucony przez hooka. Złapany wyjątek należy rzucić dalej jako HookExecutorException z podaniem jaki Hook rzucił wyjątek i jaką podał wiadomość.

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.

Przykład
@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.

  • No labels