ZeroC Ice Systemy rozproszone. Jak systemy napisane w różnych środowiskach programistycznych i językach mają się ze sobą komunikować. Usługa sieciowa SOAP bądź RES brzmi sensownie. W drugim semestrze moich studiów magisterski musiałem napisać na zaliczenie różne sposoby komunikacji. Uczelnia PJWSTK jest głównie ustawiona na Jave a co zatem idzie na rozwiązanie CORBA polegającą na komunikacji pomiędzy środowiskami na bardzo niskim poziomie. Jest to szybsze rozwiązanie niż SOAP i REST.

CORBA jest przestarzałą technologią i nie był to jedyny problem. Chciałem cały projekt zaliczyć pisząc tylko aplikację w C# i środowisku .NET.

W .NET nie ma oficjalnego sterownika do CORBA, a nie oficjalny sterownik IIOP.NET jest ciężki w użyciu, jak i martwy. Próbowałem go użyć przez 4 godziny i nie udało mi się nawet wyczarować programu Hello World. Nie mówiąc o dziwnym uczuciu jakby używał C# i .NET  jakby to było środowisku firmy Sun <bryyy>.

CORBA więc nie pogoda z .NET, więc jeśli nie pracujesz z COBOLEM, który musi komunikować się z Javą jego nauka jest bezcelowa. Przedmiot zakładał użycie CORBA, a aby nie pisać egzaminu, musiałem znaleźć odpowiednik tej technologii i znalazłem jak na ironie w prezentacjach z inne uczelni. Przynajmniej inne uczelnie prowadzą przedmiot "Systemy rozproszone" bardziej w kierunku .NET.

Jeśli więc chcemy użyć rozwiązania CORBA, ale nowocześniej i pod .NET to technologia ICE – ZeroC jest odpowiedzią.

http://www.zeroc.com/download.html

Okej, o co chodzi z CORBA I ZeroC Ice

Zapewne zadaje sobie to samo pytanie, co ja. Jeśli możemy tworzyć usługi sieciowe w SOAP i REST i w taki sposób komunikować się z systemami to, dlaczego chcielibyśmy użyć CORBA czy ZeroC Ice.

Odpowiedź jest prosta chodzi wydajność.

Wydajność polega na skutecznej serializacji informacji oraz na szybkość algorytmów ich odbierania. Wszystko odbywa się na bardzo niski poziomie więc wydajność jest podkręcona w tym wypadku na maksa.

Nie powiem, gdy pisałem ten projekt na studiach lubiłem poczytać o tym, jak ZeroC jest faktycznie szybsze niż CORBA. Artykuł znajduje się tutaj.

Kolejną wadą CORBA wynika z faktu takiego, że ta technologia popadała w sidła negatywnego zjawiska zwanego "Design by Committee". Specjalny komitet decydował o tym, co ma być specyfikacji CORBA. Wiele osób uważa swoją słuszność i aby dogodzić wszystkich, wiele funkcjonalności jest wdrażanych równocześnie, nawet jeśli się one kłócą ze sobą.  W wyniku tego CORBA jest skomplikowaną i złożoną technologią bardziej niż jest to potrzebne.

API ZeroC zdecydowanie jest prostsze. Zrozumiałem co się w nim dzieje po 20 minutach. CORBA nie uruchomiłem przez 4 godziny.

Wiemy, że CORBA nie mapuje C# mapuje ona tylko C++, Jave i Cobol.

Jakie więc języki mapuje ZeroC. Jest ich dość wiele: C++, Java, Python, Ruby, PHP. Do listy można dołączyć nawet Objective-C i iPhone, ale ten topik jest bardziej złożony.

image

Nie mogę uwierzyć, że po prawie dwóch latach fascynacją tą technologią wciąż została.

image

ZeroC używa "kromek" – (Slice). Definicja obiektów i pośredników wykonujących metody znajduje się w pliku "slice". Plik slice dynamicznie generuje potrzebny kod w zależności od środowiska.

Kolejną zaletą Zero-C jest współpraca z narzędziami developerskimi jak Visual Studio i Eclipse. Chociaż jest on do tyłu z VS 2013.

image

Napiszę więc prostą aplikację w C# która będzie wysłać komunikat do aplikacji napisanej w Javie.

Instalacja ZeroC i Visual Studio

Instalacja nie jest wielką filozofią.

ice-01

Warto zwrócić uwagę na projekty demo, które instalują się domyślnie w folderze "Moje Dokumenty".

Piszemy kod

Interfejs nie jest nam potrzebny. Do pokazania działania ZeroC wystarczy aplikacja konsolowa. Usunąłem pewne zbędne referencje, ale ty nie musisz tego robić.

ice-02

Do działania z ZeroC będą potrzebne jego biblioteki. Wszystko można ustawić w kreatorze "Ice Configuration". Wybieramy go w menu pobocznym naszego projektu .

image

Zaznaczamy następujące opcję. Możesz ustalić katalog, w którym dynamicznie klasy będą generowane, o czym później. Istnieje wiele kompilatorów, ale w tym prostym projekcie wystarczy "IceSLL".

image

Pamiętaj, że na chwilę obecną plugin i ZeroC współpracuje tylko z Visual Studio 2012 i 2010.

imageimage

Teraz przejdź do głównej filozofii technologii takiej jak ZeroC. Będziemy dodawać "kromki". Brzmi to głupio i zapewne nie jest to oficjalne tłumaczenie więc będę używał angielskiej nazwy "slice". "Plaster" nie brzmi lepiej.

ice-05

Plik "slice" ma rozszerzenie .ice i powinien się znajdować w kreatorze "Add New Item".

ice-06

Nazwijmy plik ".ice" "Hello". Po dodaniu pliku zauważ, że do solucji została także dodany plik "Hello.cs". Ten plik zostaje wygenerowany na podstawie pliku "slice", który teraz jest pusty.

Slice

W systemach rozproszonych obiekt wysłany przez server i później odebrany przez klienta ma swoją strukturę. Ta struktura będzie jednak inaczej wyglądać w wyniku różnic wynikających z  języków programistycznych. 

Plik "slice" jest pośrednikiem. Obrazuje on wzór obiektów, które będą wyglądać tak samo w różnych językach programowania. Oczywiście istnieje pewne ograniczenia wynikające ze wzoru "slice".

Rozwiązanie te jest genialne. Raz napisany wzorzec "Slice" może być przekazany do innych środowisk programistycznych. Te środowiska na swój sposób wygenerują obiekty klas , które będą używane w komunikacji. Jak się domyślasz przyspiesza to prace programisty oraz zapewnia spójną strukturę pomiędzy klientem a serwerem.

Składnia "slice" jest interesującą lekturą, zwłaszcza że mapowanie w każdy inny języku działa trochę inaczej. Gdy pisałem swój projekt przeczytałem całą dokumentację.  W tym projekcie użyje tylko niewielkiej możliwości kompilatora "Slice".

Na początku pliku "Slice" definiujemy kompilator "ZeroC Ice".

#ifndef SIMPLE_ICE
#define SIMPLE_ICE

Slice nie ma kolorowania składni.

Później definiujemy moduł, który w C# i w Javie zostanie wydrukowany jako przestrzeń nazw.

module Demo {

Na początek zdefiniuje klas "TimeOfPrint". Obecnie plik "Hello.ice" wygląda tak.

#ifndef SIMPLE_ICE
#define SIMPLE_ICE


module Demo {

class TimeOfPrint {
    byte hour; // 0 - 23
    byte minute; // 0 - 59
    byte second; // 0 - 59
    byte day;
    byte month;
    short year;    
};

};

#endif

Po zapisie pliku klasa "TimeOfPrint" powinna być utworzona. ZeroC Ice stworzył wiele klas na podstawie tego "slice", ale interesuje nas klasa "TimeOfPrint".

image

Klasa też posiada konstruktor ze wszystkim stworzonymi polami.

image

Pola ustalone przez nas zostały wydrukowane jako pola klasy.

image

Dodając ["clr:property"] mogę ustalić dla C# czy dane pole będzie właściwością. Jeśli dodam ten atrybut do całej klasy wszystkie pola będą właściwościami. Oczywiście w Javie nie ma właściwości i klasa nie zostanie tak utworzona.

["clr:property"]class TimeOfPrint {
    byte hour; // 0 - 23
    byte minute; // 0 - 59
    byte second; // 0 - 59
    byte day;
    byte month;
    short year;    
};

image

Jak zapewne zauważyłeś ZeroC Ice nie posiada typów złożonych. Ma to sens, bo jak typ DateTime miałby być wydrukowany przykładowo C++.

image

Jak definiować kolekcję elementów? W usłudze nie będziemy przesyłać pojedynczego elementu. W tym celu mamy wyrażenie "sequence". Dodając do niej atrybut ["clr:generic:List"] mogę określić jak lista zostanie wygenerowana w C#. Operowanie na ArrayList jest trochę żałosne.

["clr:property"]class SomeData {
    string Text; 
};

["clr:generic:List"]sequence MyList;

Kolejna klasa może w sobie zawierać zdefiniowane wcześniej kolekcje i klasy.

["clr:generic:List"]sequence MyList;

["clr:property"]class Message{
    MyList list;
    TimeOfPrint whenPrinted;
};

Wyjątki mogą występować w komunikacji pomiędzy serwerem a klientem. Możemy definiować swoje własne wyjątki w "slice" i później jej używać, gdy coś pójdzie nie tak jak przewidzieliśmy.

exception  MyJavaPrinterError {
    string MyMessage;
};

W Slice możemy także definiować typy wyliczeniowe.

enum PrintMode { WithNewLine, WithDoubleNewLine , WithOutNewLine };

Mamy już klasy,kolekcję, typy wyliczeniowe, ale do przesyłu danych potrzebujemy metody. Oto deklaracja interfejsu, który będzie wykonywał metodę po stronie serwera. Przyjmuje ona obiekt klasy "Message" oraz typ wyliczeniowy i może wyrzucić wyjątek "MyJavaPrinterError".

interface Printer
{
    void printString(Message t,PrintMode mode) throws  MyJavaPrinterError;
};

To wszystko, jeśli chodzi plik "slice". Przejdźmy do kodu po stronie  C# czyli klienta.

O tym w następnej części.