ΤΟ ODMG ΚΑΙ ΟΙ ΓΛΩΣΣΕΣ ΠΡΟΓΡΑΜΜΑΤΙΣΜΟΥ ΠΟΥ ΠΡΟΤΕΙΝΕΙ Γλώσσα Ορισμού Αντικειμένων (Object Definition Language - ODL) H ODL είναι μια γλώσσα που χρησιμοποιείται για να δηλώσει διαπροσωπείες (interfaces) σε τύπους αντικειμένων που ακολουθούν το μοντέλο αντικειμένων του ODMG-93 και έχει σκοπό να παρέχει μεταφερσιμότητα των σχημάτων των βάσεων δεδομένων. Κάποιες από τις αρχές σχεδίασης της ODL είναι οι εξής: Η ODL πρέπει να υποστηρίζει όλες τις σημασιολογικές δομές του ODMG μοντέλου αντικειμένων. Η ODL δε χρειάζεται να είναι μια πλήρης προγραμματιστική γλώσσα, αλλά μια γλώσσα προσδιορισμού διαπροσωπειών υπογραφών (interface signatures). Η ODL θα πρέπει να είναι ανεξάρτητη από προγραμματιστικές γλώσσες. Η ODL θα πρέπει να είναι συμβατή με την Interface Definition Language του OMG. Η ODL θα πρέπει να είναι επεκτάσιμη. Η ODL θα πρέπει να είναι πρακτική
Ακολουθεί το παράδειγμα ενός υποτυπώδους σχήματος σε ODL (με έντονα γράμματα φαίνονται οι δεσμευμένες λέξεις της ODL) interface Person ( extent people) attribute String name; attribute Struct Address Unsigned Short number, String Street, String city_name address; relationship Person spouse inverse Person::spouse; relationship Set<Person> children inverse Person::parents order by birth_date relationship List<Person> parents inverse Person::children; void birth (in String name); Boolean marriage (in String person_name) raises (no_such_person); Unsigned Short ancestors (out Set<Person> all_ancestors)raises (no_such_person); void move (in String new_address); ; interface Employee: Person ( extent employees key(name, id)) attribute Short id; attribute Unsigned Short annual_salary; ; interface City ( extent cities key city_code) attribute Unsigned Short city_code; attribute String name; attribute Set<Person> population; ;
Object Query Language - OQL Η OQL βασίζεται στο μοντέλο αντικειμένων του ODMG. Η OQL (στην τελευταία της έκδοση) είναι πολύ κοντά στην SQL 92. Οι επεκτάσεις που της δίνει είναι οι ιδέες του αντικειμενοστρεφούς μοντέλου (όπως σύνθετα αντικείμενα, ταυτότητα αντικειμένου, εκφράσεις μονοπατιών, πολυμορφισμός, κλήση μεθόδων, late binding). Η OQL παρέχει την ευκολία της άμεσης διαχείρισης για συλλογές αντικειμένων. Η OQL είναι μια γλώσσα όπου οι τελεστές μπορούν να συνδυαστούν ελεύθερα, αρκεί τα τελούμενα να σέβονται το σύστημα τύπων. Με τον τρόπο αυτό, το αποτέλεσμα της ερώτησης είναι ένα αντικείμενο που έχει τύπο που ανήκει στην ιεραρχία του ODMG και ως εκ τούτου μπορεί να ερωτηθεί ξανά. Η OQL δεν είναι από μόνη της υπολογιστικά πλήρης. Δεδομένου ότι οι OMLs και η OQL βασίζονται στο ίδιο σύστημα τύπων μπορεί κάποιος μέσα στις ερωτήσεις να καλεί μεθόδους (και αντίστροφα οι μέθοδοι να περικλείουν ερωτήσεις στην υλοποίησή τους). Η OQL δεν παρέχει τελεστές για αλλαγές (updates) αλλά βασίζεται στις μεθόδους των αντικειμένων, που έχουν καθοριστεί γι' αυτό το σκοπό. Η OQL παρέχει δηλωτικό τρόπο προγραμματισμού και έτσι μπορεί να βελτιστοποιείται εύκολα. Η OQL έχει εύκολα καθορίσιμα σημασιολογικά στοιχεία (semantics).
//Schema definition in C++ ODL class City; struct Address int number; String street; Ref<City> city; Address(); Address(int, const char*, const Ref<City> &); ; class Person: public Persistent_Object public: //Attributes String name; Address address; //Relationships Ref<Person> spouse inverse spouse; List<Ref<Person>> children inverse parents; List<Ref<Person>> parents inverse children; //Operations Person(const char* pname); void birth(const Ref<Person> &child); void marriage(const Ref<Person> &with); Ref<Set<Ref<Persons>>> ancestors() const; void move(const Address &) //move to a new address //Extension static Ref<Set<Ref<Person>>> people static const char * const extent_name; ; class Employee : public Person public: //Attributes int id; int annual_salary; //Operations Employee(int, int); //Extension static Ref<Set<Ref<Employee>>> employees; static const char * const extent_name; ;
class City : public Persistent_Object public: //Attributes int city_code; String name; Ref<Set<Ref<Perosn>>> population; //Operations City(int, const char*); //Extension static Ref<Set<Ref<City>>> cities; static const char * const; ; Aς υποθέσουμε ότι ο C++ ODL preprocessor παρήγαγε ένα αρχείο με όνομα "schema.hxx", που περιέχει τον ορισμό του παραπάνω σχήματος με standard C++ ορισμούς, ισοδύναμους με αυτούς για τις κλάσεις της C++ ODL. Ακολουθεί ο κώδικας υλοποίησης των μεθόδων σε C++ OML. //Classes implementation in C++ #include "schema.hxx" //Address struct Address::Address(int pno, const char* pstr, const Ref<City> &pcity) : number(pno),street (pstr), city(pcity) Address::Address(): number(0),street(0), city(0) //Class Person const char * const Person::extent_name = "people"; Person::Person(const char * pname): name(pname) people->insert_element(this); void Person::birth(const Ref<Person> &child) children.insert_element_last(child); if (spouse!= 0) spouse->children.insert_element_last(child);
void Person::marriage(const Ref<Person> &with) spouse = with; Ref<Set<Ref<Person>>> Person::ancestors() Ref<Set<Ref<Person>>> the_ancestors = new Set<Ref<Person>>; int i; for (i=0; i< 2; i++) if (parents[i]!= 0) the_ancestors->insert_element(parents[i]); Ref<Set<Ref<Person>>> grand_parents = parents[i]- >ancestors(); the_ancestors->union_with(*grand_parents); grand_parents.delete_object(); return the_ancestors; void Person::move(const Address &new_addr) if (address.city!= 0) address.city->population->remove_element(this); new_addr.city->population->insert_element(this); address = new_addr; mark_modified(); //necessary when an attribute changes //Class Employee const char* const Employee::extent_name = "employees"; Employee::Employee(const char *pname, int eid, int esalary): Person(pname),id(eid), salary(esalary) employees->insert_element(this);
//Class City const char * const City::extent_name = "cities" ; City::City(int code, const char* cname) : city_code(code), name(cname) cities->insert_element(this); Mε βάση και τις παραπάνω δηλώσεις των μεθόδων, μπορεί κανείς να αναπτύξει μια εφαρμογή σε C++ OML. #include <iostream.h> #include "schema.hxx" static Database dbobj; static Datadase * database = &dbobj; void Load() Transaction load; load begin; //Create extensions Person::people = new(database) Set<Ref<Person>>; Employee::employees = new(database) Set<Ref<Employee>>; City::cities = new(database) Set<Ref<City>>; database->set_object_name(person::people, Person::extent_name); database->set_object_name(employee::employees, Employee::extent_name); database->set_object_name(city::cities, City::extent_name); //3 Persons Ref<Person> God, Adam, Eve; God = new(database) Person("God"); Adam = new(database) Person("Adam"); Eve = new(database) Person("Eve"); //1 employee
Ref<Employee> Snake; Snake = new(database) Employee("Snake", 0, 0); //1 Address Address Paradise(7, "Apple", new(database) City(0, "Garden)); Adam move(paradise); Eve->move(Paradise); God->birth(Adam); Adam->marriage(Eve); load.commit; static void print_persons(const Collection<Ref<Person>> &s) Ref<Person> p; iterator<ref<person>> it = s.create_iterator(); while (it.next(p)) cout << p->name << "lives in" << p->address.city->name; void Show() Transaction show; show.begin(); Person::people = database->lookup_object(person::extent_name); City::cities = database->lookup_object(city::extent_name); Employee::employees = database->lookup_object(employee::extent_name); print_persons(*person::people); show.commit(); main() database->open("family"); Load(); Show(); database->close();
Smalltalk Binding ODL Declarations ODL Compiler Meta Objects Class O bjects Object Instances Language Binding Object Instances D atabase Im age Object subclass: #Address instancevariablenames: 'number street city ' classvariablenames: '' pooldictionaries: '' category: 'ODMG-Examples' "attributes" number "return the number" ^number number: anumber "set the number" ^number := anumber street "return the street" ^street street: astreet "set the street" ^street := astreet city
"return the city" ^city city: acity "set the city" ^city := acity Object subclass: #Person instancevariablenames: 'name address spouse children parents ' classvariablenames: 'People' pooldictionaries: '' category: 'ODMG-Examples' "attributes" name "return the id" ^name name: aname "set the name" ^name := aname address "return the address" ^address address: anaddress "set the address" ^address := anaddress "inverses" spouse "return the spouse" ^spouse formspouse: aperson "create a new couple" aperson becomespouse: self. self becomespouse: aperson.
dropspouse: aperson "drop the spouse relationship" aperson becomespouse: nil. self becomespouse:nil. children "return the children" ^children ifnil: [children := Set new] parents "return the Parents" ^parents ifnil: [parents := List new] formkin: aperson "aperson becomes the child of the receiver" aperson becomechild: self. self becomeparent: aperson. dropkin: aperson "aperson is no longer the child of a receiver" aperson removeparent: self. self removechild: aperson. "administer inverses" becomespouse: aperson "become the spouse of aperson" ^spouse := aperson becomeparent: aperson "become the parent of aperson" ^self children add: aperson becomechild: aperson "become the child of aperson" ^self parents add: aperson removeparent: aperson "remove aperson from the receiver's parents" ^self parents remove: aperson removechild: aperson
"remove aperson from the receiver's children" ^self children remove: aperson "other methods" birth: ababy "a couple has a baby" x self formkin: ababy. x := self spouse. x isnil iffalse: [x formkin: ababy]. marriage: aperson "marry somebody" self formspouse: aperson move: anaddress "move to a new address" oldcity newcity oldcity := self address city. oldcity isnil iffalse: [oldcity removepopulation: self]. newcity := anaddress city. newcity isnil iffalse: [newcity addpopulation: self]. self address: anaddress. ancestors "find the ancestors of the receiver" grandparents theancestors grandparents := Set new. theancestors := Set new. theancestors union: (self parents). self parents do: [:each each parents do: [:each1 grandparents add: each1] ]. ^theancestors union: grandparents
Object subclass: #City instancevariablenames: 'citycode name population' classvariablenames: 'Cities' pooldictionaries: '' category: 'ODMG-Examples' "attributes" citycode "return the citycode" ^citycode citycode: acitycode "set the citycode" ^citycode := acitycode name "return the name" ^name name: aname "set the name" ^name := aname population "return the population" ^population ifnil: [population := Set new] "administrate the set" addpopulation: aperson "add a Person to the population of the City" ^self population add: aperson removepopulation: aperson "remove a Person to the population of the City" ^self population remove: aperson
Person subclass: #Employee instancevariablenames: 'id annualsalary ' classvariablenames: 'Employees' pooldictionaries: '' category: 'ODMG-Examples' "attributes" id "return the id" ^id id: anid "set the id" ^id := anid annualsalary "return the annualsalary" ^annualsalary annualsalary: anannualsalary "set the annualsalary" ^annualsalary := anannualsalary