Grips/Cmd version 1.05 ====================== NAME Grips::Cmd - Perl-Schnittstelle zur grips-open Skriptsprache INSTALLATION To install this module type the following: perl Makefile.PL make make test make install DEPENDENCIES This module requires these other modules and libraries: Carp IO::Socket Data::Dumper Parse::RecDescent Grips::Gripsrc SYNOPSIS use grips::Cmd; $grips = new Grips::Cmd(host => 'gripsdb.dimdi.de', port => 5101); $grips->login(user => '1234abcd', pwd => ""); $grips->setAttribute(grips_object_name => $grips->getSessionID, timeout => 600); $grips->defineBase(grips_object_name => $grips->getSessionID, id => "bas1", dbs => ["ml66"]); $grips->open(grips_object_name => "bas1"); $searchResponse = $grips->search(grips_object_name => "bas1", 'query.string' => "nix"); $hits = $searchResponse->{result}->{hits}; for (1..$hits) { $gdbResponse = $grips->getDocBody(grips_object_name => 2, subset => $_, layout => "CBI_HTML", req_modifier => "CBI_FULL"); $htmlText = $gdbResponse->{doc_body}; print $htmlText; } $grips->close(grips_object_name => "bas1"); $grips->logout(grips_object_name => $grips->getSessionID); DESCRIPTION Dieses Modul implementiert eine Perl-Schnittstelle zur grips-open Skriptsprache. Dabei ersetzt es die flache Skriptstruktur sowohl beim Request als auch bei der Response durch Perl-Datenstrukturen. Struktur des Requests Die grips-open-Skriptfunktionen werden als Methoden auf dem grips::Cmd-Objekt aufgerufen. Dabei fangen sämtliche Methoden mit einem Kleinbuchstaben an und heissen ansonsten exakt wie die Skriptfunktionen. Die Parameter für den Request werden den Methoden in der perlüblichen Hash-Schreibweise übergeben: $grips->methodenName(par1 => 'wert1', par2 => 'wert2'); Hat ein Parameter die Form einer Liste, muss diese als Referenz auf einen Array bzw. als anonymer Array übergeben werden: $grips->methodenName(par1 => \@werte); oder $grips->methodenName(par1 => ['wert1', 'wert2']); Desweiteren muss bei Methoden allgemein der grips-Script-Objektname als Parameter 'grips_object_name' (oder alternativ '_') übergeben werden, also etwa $grips->getDocBody(_ => 2, subset => 1-10, layout => "CBI_HTML", req_modifier => "CBI_FULL"); wo die Methode "getDocBody()" auf dem Search-Result-Objekt mit der ID '2' aufgerufen wird oder $grips->close(_ => "bas1"); wenn das base-Objekt mit der ID "bas1" geschlossen werden soll. Hierbei muss angemerkt werden, dass diese Vorgehensweise nicht ganz durchgehend implementiert wurde. Bei einigen Methoden müssen möglicherweise andere Parameter gesetzt werden. Struktur der Response Die grips-Skript-Response wird in eine komplexe Perl-Datenstruktur nach folgenden Regeln umgesetzt: Sämtliche Methoden liefern eine Referenz auf einen Hash zurück. Die Parameter der Response bilden Schlüssel dieses Hashs, die je nach Struktur der Response wieder unterschiedliche Strukturen annehmen können. Ist der Wert eines solchen Schlüssels ein schlichter skalarer Wert, wird dies auch in der Perl-Datenstruktur so abgebildet. Ist der Wert in der grips-Response eine Liste, so wird er in der Perl-Datenstruktur als Array abgebildet. Hierbei ist zu beachten, dass in der grips-Response die Listennumerierung mit 1, in der Perl-Datenstruktur aber natürlich mit 0 beginnt. Kommt ein Schlüssel in der grips-Response mehrfach vor, wird er in der Perl-Datenstruktur in einen Hash umgesetzt. Ein Beispiel macht dies vielleicht deutlicher: Eine grips-Response mit der Struktur {CBI_RESPONSE=103960370811963.0000005 request=bas1.Search status=CBI_OK message=Base.Search: Search was o.K. result.id=2 result.hits=1 result.query=ND=381095 } wird in folgende Perl-Datenstruktur umgewandelt $response = { 'result' => { 'hits' => '1', 'id' => '2', 'query' => 'ND=381095' }, 'status' => 'CBI_OK', 'message' => 'Base.Search: Search was o.K.', 'CBI_RESPONSE' => '103960370811963.0000005', 'request' => 'bas1.Search' }; Zur Betrachtung der Perl-Datenstruktur ist das "Data::Dumper"-Modul sehr hilfreich, mit dem auch die obige Ausgabe produziert wurde ("print Dumper $response;"). Listen in der grips-Response werden folgendermassen umgesetzt: {CBI_RESPONSE=103960871526624.0000006 request=2.GetDocs status=CBI_OK message=SearchResult.GetDocs: end of subset docs_num=2 doc(1).id=1 doc(1).title=In vitro effects of NIPRISAN (Nix-0699). doc(1).$DBNAME=MEDLINE doc(1).$DBKEY=ML66 doc(1).$COPYR=NLM doc(1).TI=In vitro effects of NIPRISAN (Nix-0699). doc(2).id=2 doc(2).title=Mitochondrial death protein Nix. doc(2).$DBNAME=MEDLINE doc(2).$DBKEY=ML66 doc(2).$COPYR=NLM doc(2).TI=Mitochondrial death protein Nix. } wird zu $response = { 'status' => 'CBI_OK', 'docs_num' => '2', 'message' => 'SearchResult.GetDocs: end of subset', 'CBI_RESPONSE' => '103960863726019.0000006', 'doc' => [ { 'DBNAME' => 'MEDLINE', 'title' => 'In vitro effects of NIPRISAN (Nix-0699).', 'COPYR' => 'NLM', 'DBKEY' => 'ML66', 'id' => '1', 'TI' => 'In vitro effects of NIPRISAN (Nix-0699)' }, { 'DBNAME' => 'MEDLINE', 'title' => 'Mitochondrial death protein Nix.', 'COPYR' => 'NLM', 'DBKEY' => 'ML66', 'id' => '2', 'TI' => 'Mitochondrial death protein Nix.' } ], 'request' => '2.GetDocs' }; METHODS gsc-Methoden Das Modul unterstützt einen grossen Teil der Methoden der grips-open-Skriptsprache. Definitiv funktionieren folgende Methoden: login(); .getAttributes(); .setAttribute(); .setAttributePermanent(); .getSubjectList(); .getBaseList(); .getIndexedBaseList(); .getApplicationInfo(); .defineBase(); .logout(); .open(); .setLimit(); .getFieldsInfo(); .browseIndex(); .search(); .removeDuplicates(); .getResults(); .deleteResult(); .getDocForUpdate(); .getNewDocKey(); .storeDocument(); .lock(); .unlock(); .close(); .sort(); .getDocBody(); .getDocs(); .getField(); .getFullTextInfo() .analyseTerms(); .analyseTermsStatistic(); .getSupplList(); .getSupplInfo(); Diverse andere Methoden sollten automatisch funktionieren, für einige Methoden ist allerdings eine Spezialimplementierung erforderlich. Dies kann bei Bedarf auf Anfrage an den Autor hin geschehen. Die Parameter der Methoden entprechen den im grips-open Script verwendeten. Das in spitzen Klammern vorangestellte grips-Objekt sollte bei allen Methoden über den Parameter 'grips_object_name' (oder alternativ '_') referenziert werden, also z.B. $grips->search(grips_object_name => "bas1", ...) wenn das Base-Object in defineBase() "bas1" genannt wurde, $grips->getField(grips_object_name => 2, ...) wenn ein Feld des Profiltabelleneitrags mit der ID 2 gefunden werden soll etc. Darüber hinaus hat das Modul folgende eigene Methoden: new() Legt ein neues grips::Cmd-Objekt an. Parameters * "host" - Host des Socket-CBI-Dämons, also z.B. gripsdb.dimdi.de. Kann weggelassen werden, ist dann app01testgrips.dimdi.de. * "port" - Port des Socket-CBI-Dämons. Kann weggelassen werden, ist dann 5101. * "sessionID" - Session-ID für die Session. Kann weggelassen werden, wird dann generiert aus "unix-Epochensekunden.pid" croaks if ... * ... keine Verbindung zum CBI-Dämon hergestellt werden kann getHost() Liefert den Host des Script-CBI-Dämons. getPort() Liefert den Port des Script-CBI-Dämons. getSessionID() Liefert die Session ID checkGripsResponse() Überprüft, ob der Status der Response CBI_OK bzw. ein anderer erwarteter Status ist. Parameters * 1. Parameter - (HARD|SOFT) wenn HARD, wird eine Exception geworfen, sonst wird eine Warnung ausgegeben. * 2. Parameter - die Response einer grips-Skriptfunktion * 3. Parameter - der erwartete Status der script-Response. Wenn der Parameter nicht übergeben wird, 'CBI_OK' croaks if ... * ... s.o. * ... wenn der Wert des ersten Parameter das nicht entweder HARD oder SOFT ist Beispiel $response = checkGripsResponse("HARD", $grips->defineBase(_ => $grips->getSessionID, id => "bas1", dbs => ["ml66"]), 'CBI_OK'); wirft Exception, wenn defineBase() nicht CBI_OK liefert connectionIsAlive() Liefert 1, wenn noch eine Verbindung zum Socket-CBI-Dämon besteht, sonst 0. EXPORT_OK checkGripsResponse(); .gripsrc-Datei Im $HOME-Verzeichnis des aufrufenden Users kann eine Datei namens ".gripsrc" mit der Berechtigung 700 angelegt werden, in der Host, Usercode und Passwort angegeben werden können. In diesem Fall müssen Usercode und Passwort nicht der Login-Methode mit übergeben werden. Die gripsrc-Datei kann folgendermassen aussehen: host app01grips.dimdi.de pwd blubb user abcd1234 host app01testgrips.dimdi.de user wxyz9876 Hier wird für den Host gripsdb.dimdi.de der Usercode abcd1234 mit dem Passwort blubb und für den Host app01testgrips.dimdi.de der Usercode wxyz9876 ohne Passwort eingetragen. Die Verwendung einer solchen Datei empfiehlt sich sehr, da es ein Sicherheitsrisiko ist, in Perlscripten Usercode und Passwort anzugeben. ACHTUNG!!! Um böse Fallen gleich zu vermeiden: eine solche .gripsrc-Lösung funktioniert natürlich nicht in CGI-Kontexten. Hier müssen Usercode und Passwort der login()-Methode direkt übergeben werden. Wie sie dort hinkommen, ohne grosse Sicherheitslöcher zu reissen, ist eine Frage, die unabhängig von diesem Modul gelöst werden muss. VERIONS 0.01 - Rudimentäre und wenig systematisierte Funktionalität 0.80 - Dokumentation hinzugefügt - Methodenschnittstellen vereinheitlicht - alle Methoden mit Parameter grips_object_name versehen, der den Namen des grips-open-Objekts bezeichnet, auf dem der Scriptrequest ausgeführt wird - Parameter request_id vorhanden, aber deprecated - Fehler mit Session-ID korrigiert - hochzählende Transaction-ID hinzugefügt - auch login()-Methode liefert jetzt Response-Objekt zurück - Bei getDocs() kommen jetzt auch die '$'-Felder (DBKEY, COPYRIGHT etc.), allerdings ohne '$' davor 0.81 - Dokumentation erweitert - 3. Parameter (erwarteten Status) zu checkGripsResponse() hinzugefügt 1.00 - Perl-Datenstrukturen werden jetzt automatisch in beliebiger Tiefe in gsc-requests umgesetzt. Damit sollte theoretisch jeder grips-Request, der sich an die gsc-eigenen Regeln hält, funktionieren. - Alle Funktionen ausser login() und logout() geben jetzt eine Warnung aus, wenn sie ohne den Parameter "grips_object_name" aufgerufen werden. - Damit man nicht so viel tippen muss, kann statt des Parameternamens "grips_object_name" jetzt auch "_" eingegeben werden. 1.01 - Fehler bei getCost() und analogen response-Strukturen beseitigt, wo Reponsezeile die Struktur key(n)=value (im Ggs. zu keyA(n).keyB=value) hat - Open kann jetzt auch 'rd_from' und 'rd_to' - Search kann jetzt auch 'query.mode' 1.02 - Abwärtskompatibilität bei search() hergestellt: Request versteht jetzt auch wieder skalaren Parameter "query", der query.string enthält. 1.03 - Funktion connectionIsAlive() hinzugefügt. Liefert 1, wenn noch eine Verbindung zum Socket-CBI-Dämon besteht, sonst 0. 1.04 - Problem beim Parsen der Response von GetFields() behoben, wenn Periodengruppen zurückkommen. Gelöst über Funktion _cleanRetVal() - Fehler beim Parsen von #1 in Response von GetFields() behoben 1.05 - Fehler beim Parsen von Periodengruppen namens "P-Group" behoben 1.06 - Konstruktor stirbt nicht mehr, wenn kein Socket da, sondern warnt und liefert undef 1.07 - Nur Quelltextlayoutverschönerungen 1.08 - Parse::RecDescent auskomentiert, ist ja eigentlich nicht noetig 1.09 - new response syntax implementiert 1.10 - Fix package declarationAUTHOR 1.11 - Fix Makefile.PL Tarek Ahmed, COPYRIGHT Copyright (c) 2002 Tarek Ahmed. All rights reserved. This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself. SEE ALSO Grips::Gripsrc für die Entwicklung eigener grips-perl-Schnittstellen (Das Modul ist inklusive Dokumentation von Net::Netrc abgekupfert. Daher ist die Dokumentation in englisch und möglicherweise zu umfangreich und nicht ganz auf grips-Bedürfnisse zugeschnitten.)