PASOE i serwisy WebHandler cz. I
Deweloperzy aplikacji webowych z wykorzystaniem serwera PASOE mają od wersji 11.6.3 nową możliwość tworzenia serwisów typu Data Object. Są to tzw. WebHandlery, które działają z wykorzystaniem warstwy transportowej WEB (Data Object WebHandler Service).
WebHandler zapewnia bardziej wydajną i prostszą warstwę komunikacyjną niż REST. Jest napisany w ABL, łatwiej dopasować go do własnych potrzeb i ma ulepszone możliwości debugowania. Podstawową zaletą WebHandlera jest to, że daje programistom pełną kontrolę nad przychodzącymi i wychodzącymi danymi.
Warstwa WEB obsługuje żądania (requests) i odpowiedzi (responses), które używają standardowych czasowników HTTP (verbs). Obejmuje to interakcje z klientami, takimi jak WebSpeed i OpenHTTP.
Jeśli chcesz zmienić domyślny adres URL, możesz dodać dodatkowe WebHandlery i zmapować je na różne adresy URL lub zmienić odwzorowania domyślnych WebHandlerów.
Dodatkowe WebHandlery można dodać w pliku openedge.properties dla instancji OEPAS i zmapować je na określone adresy URL. Na przykład:
defaultHandler=OpenEdge.Web.CompatibilityHandler webhandler1=MyHandler:/mycustomer webhandler2=MyHandler:/mycustomer/{custid}
OpenEdge.Web.CompatibilityHandler zapewnia kompatybilność z aplikacjami WebSpeed SpeedScript i CGI Wrapper. Jest to domyślny handler używany w instancji w środowisku programistycznym.
Tworzenie tych serwisów zilustruję dwoma przykładami zaczerpniętymi z bazy wiedzy.
Zaczynamy od założenia, że mamy instancję serwera PASOE z podłączoną bazą danych sports2000.
Tworzymy nowy projekt OpenEdge. Nadajemy mu nazwę np. webh1, wybieramy typ Server i zaznaczamy warstwę transportową WEB.
Klikamy Next, sprawdzając czy do projektu jest podłączona instancją serwera aplikacji, a w ostatnim kroku upewniamy się, że jest przyłączona nasza baza danych.
Kreator tworzy od razu klasę WebHandlera, w tym przypadku webh1Handler.cls, zawierającą 3 metody: HandleNotAllowedMethod, HandleNotImplemented oraz HandleGet. Dwie pierwsze są związane z wychwytywaniem błędów. HandleGet to główna metoda, w której można przetwarzać dane otrzymane z odpowiedzi (response).
Stworzymy teraz obiekt danych. W Project Explorerze zaznaczamy nazwę projektu i prawym klikiem myszy wybieramy New -> Business Entity.
Podajemy nazwę customerBE, klikamy Next i wybieramy z bazy tabelę customer.
W efekcie jest utworzona znana z poprzednich artykułów klasa customerBE.cls.
Do klasy tej będziemy odnosić się z WebHandlera, czyli pliku webh1Handler.cls. Teraz należy zmodyfikować metodę HandleGet aby miała postać tak jak w poniższej klasie webh1Handler.cls (można skopiować cały plik klasy).
Widać, że oprogramowanie metod wymaga znajomości programowania obiektowego i odpowiednich referencji, ale daje bardzo duże możliwości. W poniższym przykładzie w odpowiedzi HTTP pobierana jest zawartość tablicy ttCustomer (z obiektu customerBE) i wyświetlana poprzez obiekt JSON.
USING Progress.Lang.*. USING OpenEdge.Web.WebResponseWriter. USING OpenEdge.Net.HTTP.StatusCodeEnum. USING OpenEdge.Web.WebHandler. USING customerBE.*. USING Progress.Json.ObjectModel.*. BLOCK-LEVEL ON ERROR UNDO, THROW. CLASS webh1Handler INHERITS WebHandler: {"customerbe.i"} /*------------------------------------------------------------------------------ Purpose: Handler for unsupported methods. The request being serviced and an optional status code is returned. A zero or null value means this method will deal with all errors. Notes: ------------------------------------------------------------------------------*/ METHOD OVERRIDE PROTECTED INTEGER HandleNotAllowedMethod( INPUT poRequest AS OpenEdge.Web.IWebRequest ): /* Throwing an error from this method results in a 500/Internal Server Error response. The web handler will attempt to log this exception. See the HandleGet method's comments on choosing a value to return from this method. */ UNDO, THROW NEW Progress.Lang.AppError("METHOD NOT IMPLEMENTED"). END METHOD. /*------------------------------------------------------------------------------ Purpose: Handler for unknown methods. The request being serviced and an optional status code is returned. A zero or null value means this method will deal with all errors. Notes: ------------------------------------------------------------------------------*/ METHOD OVERRIDE PROTECTED INTEGER HandleNotImplemented( INPUT poRequest AS OpenEdge.Web.IWebRequest ): /* Throwing an error from this method results in a 500/Internal Server Error response. The web handler will attempt to log this exception. See the HandleGet method's comments on choosing a value to return from this method. */ UNDO, THROW NEW Progress.Lang.AppError("METHOD NOT IMPLEMENTED"). END METHOD. /*------------------------------------------------------------------------------ Purpose: Default handler for the HTTP GET method. The request being serviced and an optional status code is returned. A zero or null value means this method will deal with all errors. Notes: ------------------------------------------------------------------------------*/ METHOD OVERRIDE PROTECTED INTEGER HandleGet( INPUT poRequest AS OpenEdge.Web.IWebRequest ): DEFINE VARIABLE oResponse AS OpenEdge.Net.HTTP.IHttpResponse NO-UNDO. DEFINE VARIABLE oWriter AS OpenEdge.Web.WebResponseWriter NO-UNDO. DEFINE VARIABLE oBody AS OpenEdge.Core.String NO-UNDO. DEFINE VARIABLE beCustomer AS customerBE NO-UNDO. DEFINE VARIABLE pcFilter AS CHAR NO-UNDO. DEFINE VARIABLE lcJSON AS LONGCHAR NO-UNDO. DEFINE VARIABLE jObj AS JsonObject. DEFINE VARIABLE htt AS HANDLE. jObj = NEW JsonObject(). /* Get data from the BE */ beCustomer = NEW customerBE(). beCustomer:ReadcustomerBE(INPUT pcfilter,OUTPUT DATASET dsCustomer). htt = TEMP-TABLE ttCustomer:HANDLE. htt:WRITE-JSON("JsonObject", jObj). ASSIGN oResponse = NEW OpenEdge.Web.WebResponse() oResponse:StatusCode = INTEGER(StatusCodeEnum:OK) . /* This body object can be a string or something else (JsonObject for instance) */ lcJSON= jObj:GetJsonText(). ASSIGN oBody = NEW OpenEdge.Core.String(lcJSON). ASSIGN oResponse:Entity = oBody /* HTTP messages require a content type */ oResponse:ContentType = 'application/json':u /* ContentLength is good too */ oResponse:ContentLength = oBody:Size . /* The WebResponseWriter ensures that the status line and all headers are writted out before the message body/entity. */ ASSIGN oWriter = NEW WebResponseWriter(oResponse). oWriter:Open(). /* Finish writing the response message */ oWriter:Close(). /* A response of 0 means that this handler will build the entire response; a non-zero value is mapped to a static handler in the webapp's /static/error folder. The mappings are maintained in the webapps's WEB-INF/web.xml A predefined set of HTTP status codes is provided in the OpenEdge.Net.HTTP.StatusCodeEnum enumeration */ RETURN 0. END METHOD. END CLASS.
W przeglądarce wpisujemu URL dla naszej instancji PASOE np.: http://localhost:8810/webh1/web/webh1 (lub https://localhost:8811/webh1/web/webh1 dla bezpiecznego połączenia).
W efekcie dostajemy ekran podzielony na 3 przekładki:
JSON
Raw Data
Headers