Przejdź do treści

Drivery, Konektory i adaptery

Mechanizm komunikatów EDA został zaprojektowany, tak aby współpracował z ideą driverów, konektorów i adapterów. Więcej o komunikatach w rozdzale Komunikaty

Schemat zależności pomiędzy EDA, konektorami, adapterami i sterownikami

Driver

To biblioteka dll zawierajaca kod komunikujący się z WebAPI dostawców różnych usług (np. spedytorzy, sklepy internetowe, bramki OCR, bramki rządowe, itp.). W driverze nie powinno być kodu komunikujacego się z bazą danych, gdyż zapis i odczyt danych z bazy nie jest odpowiedzialnością drivera. Dane, które są dostarczane i odbierane od drivera to klasy C# ze strukturami danych.

Adapter

Adapter służy do komunikacji między driverem a bazą danych. To on mapuje klasy struktur danych odebrane od drivera na zapis do odpowiednich tabel w BD i odwrotnie. Zwykle powinniśmy mieć jeden adapter do jednego drivera, ale jeśli dane z drivera będziemy zapisywać w bazie danych na kilka możliwych sposobów, to należy mieć więcej niż jeden adapter do jednego drivera. Np jeśli oprócz OCR faktur kosztowych (którego wyniki zapisywane są do tabel WFFACOSTINVOICE i WFFACOSTINVOICEPOS), chcemy mieć ten sam driver OCR wykorzystany do OCR faktur towarowych (którego wyniki będą zapisywane do tabel NAGFAK i POZFAK) to potrzebujemy mieć dwa różne adaptery do jednego drivera OCR.

Adapter to z założenia obiekt neosowy. Oprócz logiki mapowania danych zawiera definicję parametrów konfiguracyjnych, jeśli sterownik tego wymaga (np. klucze autoryzujące do API) oraz formę SETUP, która umożliwia podczas wdrożenia łatwą konfigurację sterownika. Adapter powinien zawierać też definicję komendy oraz handler tej komendy, który rozpocznie proces realizacji danego zadania.

Przykładem adaptera jest obiekt OCR.SKANUJTO_ADAPTER, który na podstawie konfiguracji konektora uruchamia odpowiednią metodę sterownika usługi OCR - Neos.Modules.OCR.SkanujTo (patrz Adapter OCR w Workflow).

Tworzenie nowych adapterów

Neos Expert daje nam możliwość stworzenia obiektu, który jest adpaterem poprzez wybranie opcji Obiekt jest adapterem EDA podczas tworzenia nowego obiektu, lub bezpośrednio podczas wyboru nowego rodzaju obiektu. Adapterem jest obiekt Bez źródła danych, więc wybór tej opcji, spowoduje brak możliwości zmiany Źródła danych.

W celu szybszego wyszukania adapterów jest możliwość filtracj obiektów, które są adapterami (obiekty oznaczone właściwością Obiekt jest adapterem EDA).

Konektor

Konektor pozwala połączyć ze sobą driver, adapter i konkretną konfigurację (np wybór bramki: testowa / produkcyjna, dane logowania, dodatkowe parametry) i nadać jeden wspólny symbol, do którego można się odwoływać wysyłając komendy. Jeśli chcemy skonfigurować np kilka kont logowania do jednej bramki spedytora, konfigurujemy do tego różne konektory.

Właściwy konektor będzie mógł być wybrany programowo lub przez użytkownika. Podczas wysyłania komendy do EDA zamiast podawać pełną ścieżkę handlera, który ma przetworzyć daną komedę, można podać symbol konektora. Dzięki temu EDA wyśle komendę na odpowiedni handler wraz z konfiguracją.

Konektory definiowane są za pomocą okna Administracja > Wymiana danych > Konektory EDA.

Konektory EDA

Tworzenie konektora

Note

W kontekście konektorów adapterem może być każdy obiekt neosowy, który posiada handlery na komunikaty EDA.

Dodanie nowego konektora odbywa się za pomocą akcji Dołącz.

Nowy konektor EDA

Aby zdefiniować konektor podajemy:

  • Adapter - obiekt biznesowy adaptera, do którego tworzymy konektor

  • Nazwa - przyjazna dla dewelopera i administratora nazwa konektora (np. "IAI - produkcja", "IAI - bramka testowa", itp.)

  • Grupa - symbol łączący różne konektory o takim samym przeznaczeniu. Np grupa OCR łączy konektory przeznaczone do usług OCR. Dzięki połączeniu kilku konektorów w jedną grupę, mamy możliwość określenia konektora domyślnego w grupie, a także zrealizowania programowego (przez programitę) lub interfejsowego (dla administratora lub użytkownika) wyboru dowolnego konektora z danej grupy.

  • Symbol - unikalny symbol konektora, którym będziemy programowo identyfikować konektor

  • Metoda obsługująca - w przypadku konektorów obsługujących tylko jedną komendę możemy wskazać metodę obsługującą (handler) w ramach wskazanego adaptera, która będzie wywoływana do obsługi przesłanej komendy. Jest to przydatne wtedy, gdy obok metody produkcyjnej chcemy napisać metodę testową i zdefiniować testowy konektor wskazujący właśnie tą testową metodę obsługującą. W przypadku adapterów obsługujących wiele komunikatów, najlepiej pozostawić to pole puste.

  • Identyfikator Neosa (Endpoint Prefix) - w przypadku kierowania komunikatów na inną instancję serwera Neos podajemy tutaj jego endpoint prefix. Jeśli komunikaty wysyłamy na lokalnego Neosa, to zostawiamy to pole puste.

  • Domyślny - znacznik, że dany konektor jest domyślnym w grupie.

Grupa i symbol są kluczem, po którym identyfikujemy konkretny konektor i muszą być uzupełnione.

Note

Jeżeli metoda obsługująca nie zostanie podana w definicji konektora, wówczas w momencie wysyłania komendy (metoda SendCommand) możemy podać nazwę metody obsługującej jako część parametru target. Jeśli tam także nie podamy nazwy metody obsługującej, to zostanie ona zbudowana automatycznie z nazwy klasy komendy, która jest wysyłana na konektor oraz dopisania słówka 'Handler'.

Example

Wysyłając na konektor komendę 'InvoiceOCRCommand' domyślną nazwą metody obsługującej będzie 'InvoiceOCRCommandHandler'

Okno konfiguracji parametrów konektora

Konfiguracja adaptera czasami może być bardzo szczegółowa i skomplikowana, dlatego w obiekcie adaptera można zdefiniować formę konfiguracyjną o symbolu SETUP. Forma ta jest wyświetlana w momencie konfigurowania konkretnego konektora i pozwala w wygodny i czytelny sposób wprowadzić wszystkie parametry niezbędne do prawidłowego działania usługi, z którą się komunikujemy.

Forma SETUP

Odczyt konfiguracji parametrów konektora w handlerze

Parametry skonfigurowane poprzez formę konfiguracyjną można odczytać w kodzie handlera. Aby to zrobić, należy najpierw za pomocą metody context.GetConnector() dostać się do informacji na temat konektora, na którego został wysłany komunikat. Następnie możemy użyć kolekcji Params["[nazwa parametru]"] na obiekcie konektora, aby uzyskać konkretny parametr. Jeżeli parametr nie zostanie znaleziony, to zostanie rzucony wyjątek System.Collections.Generic.KeyNotFoundException. Możemy również skorzystać z metody TryGetValue() na kolekcji parametrów.

Example

virtual public HandlerResult TestCommandHandler(ConsumeContext<TestCommand> context)
{
  //...
  var connector = context.GetConnector();

  var userName = connector.Params["username"];
  //Lub bezpieczniejsza forma
  if(!connector.Params.TryGetValue("username", out var username))
  {
    // co ma się stać w przypadku gdy brakuje wartości
  }
  //...
}

Tworzenie dynamicznego menu z grupy konektorów

W szczególnym przypadku użytkownik może móc sam wbyrać konektor, czyli konfigurację, za pomocą której łączy się z daną usługą. Jest to przydatne, jeśli chcemy, aby sam użytkownik wybrał, czy łączy się do bramki produkcyjnej czy testowej, albo z której usługi OCR-a, chce skorzystać.

Jeśli chcemy dać możliwość wyboru akcji na podstawie zdefiniowanych konektorów to możemy tego dokonać przez zwrócenie listy konektorów w danej grupie i utworzenie dynamicznej akcji popup menu.

//action to metoda, która przyjmuje identyfikator konkretnego konektora po kliknięciu na akcję ze zbudowanego menu
public void ChooseConnector(Action<string> action)
{
  //API EDA.CONNECTORS udostępnia zestaw metod do zarządzania konektorami, tutaj GetCollection zwraca listę akcji grupy OCR, które obsługują typ komunikatu InvoiceOCRCommand
  var connectors = EDA.CONNECTORS.GetCollection<InvoiceOCRCommand>("OCR").ToList();

  //budujemy kolekcję akcji wraz z ustawieniem przekazywanego pełnego identyfiaktora konektora FullSymbol
  var actions = connectors.Select(con => Actions.CreateAction(con.Name, "MI_SZUKFAK", action).SetParam(con.FullSymbol)).ToList();

  //na koniec wywołujemy pokazanie dynamicznego popup menu
  ShowPopupMenu(actions);
}

Zapis i odczyt stanu konektora

Jeżeli w obiekcie, zdefiniowana jest forma z symbolem STATE, otrzymujemy możliwość konfiguracji stanu konektora w oknie konfiguracji konektorów - przycisk Stan konektora. Parametry które, są dodane do formy STATE będą reprezentować stan konektora. Stan konektora (forma STATE) różni się od konfiguracji konektora (forma SETUP) tym, że zmiana stanu konektora możliwa jest również z poziomu kodu w metodzie handlera.

Zapis i odczyt stanu konektora umożliwiają następujące metody:

  • string GetState(EdaConnectorConfiguration edaConnectorConfiguration, string parameterName) - pobiera stan parametru na podstawie przekazanego konektora oraz nazwy parametru. Parametr o tej nazwie musi się znajdować na formie STATE obiektu adaptera.

  • void SetState(EdaConnectorConfiguration edaConnectorConfiguration, string parameterName, string value) - zapisuję stan parametru na podstawie o wskazanej nazwie. Parametr o tej nazwie musi się znajdować na formie STATE obiektu adaptera.

  • EdaConnectorConfiguration GetConnector(this ConsumeContext consumeContext) - pobiera konektor o zadanym symbolu. Obsługuje tylko wskazanie explicite dla konektora czyli <GRUPA>.<SYMBOL>.

Example

Przykład zastosowania metod GetStates, SetStates, GetConnector

public HandlerResult TestCommandHandler(ConsumeContext<TestProject.TestCommand> context)
{
  // Pobranie konektora z contextu
  var connector = context.GetConnector();
  // Ustawienie stanu parametru _param
  EDA.CONNECTORS.SetState(connector, "_param", "Nowa wartość");
  // Przypisanie do zmiennej wartosci parametru _param pobranego poprzez GetState
  var state = EDA.CONNECTORS.GetState(connector, "_param");

  return HandlerResult.Handled;
}

Cache'owanie parametrów konektora

Z uwagi na fakt, że konfiguracja konektorów jest potrzebna przy wykonywaniu handlerów to wprowadziliśmy mechanizm cache, po to, aby nie obciążać bazy danych i zwiększyć wydajność rozwiązania EDA.

Mechanizm ten działa następująco: Przy starcie systemu, Neos zadaje zapytanie do tabel SYS_EDACONNECTORS i SYS_EDACONNECTORPARAMS, a następnie konfigurację z tych konektorów przechowuje w pamięci. W momencie, gdy na 1 Neosie zmieni się konfiguracja konektora, wtedy cache jest przeładowany ponownie. Jeśli mamy konfigurację wieloneosową i zmieni się konfigurację konektora, to cache przeładuje się na wszystkich Neosach.

!!! Warning Uwaga! Zmodyfikowane stany konektorów spod bazy danych nie zostaną przeładowane przez Neosa.

Wysyłanie komend na adaptery i konektory EDA

Domyślnie komendy EDA można wysyłać bezpośrednio na obiekt i metodę obsługującą przy użyciu 'SendCommand()'

Example

public void SendTestCommand()
{
  EDA.SendCommand("TestProject.ADAPTER.TestCommandHandler", new TestProject.TestCommand { });
}      

Jeżeli w NEOS'ie zostaną zdefiniowane adaptery wówczas możliwe jest: - Wysyłanie komend na domyślny konektor w grupie wskazując nazwę grupy:

Example

public void SendTestCommand()
{
  EDA.SendCommand("TESTPROJECT", new TestProject.TestCommand { });
}      
  • Wysyłanie komend na konkretny konektor podając nazwę grupy oraz symbol konektora

Example

public void SendTestCommand()
{
  EDA.SendCommand("TESTPROJECT.TESTPROJECTADAPTER", new TestProject.TestCommand { });
}      
  • Wysyłanie komend na konkretny konektor wraz z wskazaniem metody obsługującej

Example

public void SendTestCommand()
{
  EDA.SendCommand("TESTPROJECT.TESTPROJECTADAPTER:OtherTestCommandHandler", new TestProject.TestCommand { });
}