NAME
XML::eXistDB::RPC - Contact an ExistDB via RPC
DESCRIPTION
Implementation of the full XML-RPC interface to the ExistDB. This is not just an one-on-one implementation, but some methods are smarter.
Perl interface
The methods in this module provide access to all facilities the XML-RPC protocol interface offers. However, some of these calls are on a lower level than practical in a programmers interface. A few larger wrapper methods were created, most importantly uploadDocument() and downloadDocument().
Some defaults can be set at initiation (new()), such that repetition can be avoided.
Definitions
The whole database (Repository) contains sub-databases (Collections), which can have sub-collections themselves. Any collection contains Documents (indexable XML) and Binaries (raw data). When both documents and binaries are accepted, we speak about a Resource.
Naming convensions
The XML-RPC method names are a mess: an typical example of many years of growth. To repair that, consistent naming convensions are introduced.
Any describeXXX
collects a HASH with details about XXX. Any listXXX
collects a list of XXX names. All Java typical get
method names were removed in favor of better named alternatives: sometimes list
, sometimes describe
, often something completely different. Class attribute getters and setters naming should not be used in interfaces (and very not-Perl).
Most methods already had the form "<action><class>" (like "removeCollection"), but on some random spots, the "class" was not present in the name. This has been repaired, which lowers the need to read the explanation of the methods to understand what they are doing.
Return codes
RPC is a network protocol. Just like operating calls: you shall always check the return status of each call! Of course, this module could simply ignore the existence of fault conditions, to provide a much simpler programmers interface. But keep in mind: handling error conditions is very important on the long run. A burdon for the first small programs, but a desperate need for maintainability.
All method return a LIST, where the first scalar is a return code (RC). When that code is '0', all went well. Otherwise, the code represent the transport error or the exception (refusal) as reported by the server logic. In either case, the second scalar in the returned list contains the error message. For instance,
my ($rc, $details) = $db->describeUser('guest');
$rc==0
or die "ERROR: cannot get user info for `guest': $details ($rc)\n";
METHODS
Constructors
XML::eXistDB::RPC->new(OPTIONS)
You must either specify your own XML::Compile::RPC::Client object with the rpc
option, or a destination
which will be used to create such object.
Option --Default
chunk_size 32
compress_upload 128
destination <undef>
password 'guest'
prettyprint_upload <false>
repository '/db'
rpc <undef>
schemas <created>
user 'guest'
. chunk_size => KILOBYTES
Send or download data in chunks (fragments) of this size when the size exceeds this quantity. If 0
, then chunking is disabled.
. compress_upload => KILOBYTES
Compress the upload of resources when their size is over this number of KILOBYTES in size. This will cost performance mainly on the client.
. destination => URI
Where the RPC server is (the ExistDB access point)
. password => STRING
. prettyprint_upload => BOOLEAN
. repository => STRING
The repository; the top-level collection.
. rpc => OBJECT
. schemas => OBJECT
When you need to do complex things with the eXist schema's, you may prepare an XML::eXistDB object beforehand. However, that shouldn't be needed under normal cicumstances. By default, such object is created for you.
. user => USERNAME
Used as default when a username is required. For now, that is only used by lockResource().
Helpers
$obj->schemas
Returns the XML::eXistDB object which contains all eXistDB specific schema information. At first call, the object will get created for you. Once created, you'll always get the same.
$obj->trace
Returns the trace information from the last command executed over RPC. Nearly all methods in this class only perform one RPC call. You can find the timings, http request, and http response in the returned HASH.
Format
A number of methods support formatting options, to control the output. With the method call, these parameters can be passed as list with pairs.
indent: returns indented pretty-print XML. yes|no
encoding: character encoding used for the output. <string>
omit-xml-declaration: XML declaration to the head. yes|no
expand-xincludes: expand XInclude elements. yes|no
process-xsl-pi: apply stylesheet to the output. yes|no
highlight-matches: show result from fulltext search.elements|attributes|both
stylesheet: to apply. rel-path from database <path>
stylesheet-params: stylesheet params <HASH>
The use of the "stylesheet-params" is simplified compared to the official XML-RPC description, with a nested HASH.
Sending XML
Some method accept a DOCUMENT which can be a XML::LibXML::Document node, a string containing XML, a SCALAR (ref-string) with the same, or a filename.
Repository
$obj->backup(USER, PASSWORD, TOCOLL, FROMCOLL)
Returns success. Create a backup of the FROMCOLL into the TOCOLL, using USERname and PASSWORD to write it. There is also an Xquery function to produce backups.
example:
my ($rc, $ok) = $db->backup('sys', 'xxx', '/db/orders', '/db/backup');
$rc==0 or die "$rc $ok";
$obj->hasCollection(COLLECTION)
Does the COLLECTION identified by name exist in the repository?
example:
my ($rc, $exists) = $db->hasCollection($name);
$rc and die "$exists (RC=$rc)";
if($exists) ...
$obj->hasDocument(DOCNAME)
Returns whether a document with NAME exists in the repository.
example:
my ($rc, $exists) = $db->hasDocument($name);
if($rc==0 && $exists) ....
$obj->isXACMLEnabled
Returns whether the eXtensible Access Control Markup Language (XACML) by OASIS is enabled on the database.
example:
my ($rc, $enabled) = $db->isACMLEnabled;
if(!$rc && $enable) { ... }
$obj->shutdown([DELAY])
Shutdown the database. The DELAY is in milliseconds.
example:
my ($rc, $success) = $db->shutdown(3000); # 3 secs
$rc==0 or die "$rc $success";
$obj->sync
Force the synchronization of all db page cache buffers.
example:
my ($rc, $success) = $db->sync;
Collections
$obj->collectionCreationDate([COLLECTION])
[non-API] Returns the date of the creation of the COLLECTION, by default from the root.
example:
my ($rc, $date) = $db->collectionCreationDate($coll);
$rc and die "$rc $date";
print $date; # f.i. "2009-10-21T12:13:13Z"
$obj->configureCollection(COLLECTION, CONFIGURATION, OPTIONS)
The CONFIGURATION is a whole .xconfig
, describing the collection. This can be a XML::LibXML::Document node, a stringified XML document, or a HASH.
When the CONFIGURATION is a HASH, the data will get formatted by XML::eXistDB::createCollectionConfig().
The configuration will be placed in /db/system/config$COLLECTION
, inside the database.
Option --Default
beautify <new(prettyprint_upload)>
. beautify => BOOLEAN
Produce a readible configuration file.
example:
my %index1 = (path => ..., qname => .., type => ...);
my @indexes = (\%index1, \%index2, \%index3);
my %fulltext = (default => 'none', attributes => 0, alphanum => 0);
my %trigger1 = (parameter => [ {name => 'p1', value => '42'} ];
my @triggers = (\%trigger1, \%trigger2);
my %config =
( index => {fulltext => \%fulltext, create => \@indexes}
, triggers => {trigger => \@triggers};
, validation => {mode => 'yes'}
);
my ($rc, $success) = $db->configureCollection($name, \%config);
$obj->copyCollection(FROM, TO | (TOCOLL, SUBCOLL))
Copy the FROM collection to a new TO. With three arguments, SUBCOLL is a collection within TOCOLL.
example:
my ($rc, $succ) = $db->copyCollection('/db/from', '/db/some/to');
my ($rc, $succ) = $db->copyCollection('/db/from', '/db/some', 'to');
$obj->createCollection(COLLECTION, [DATE])
Is a success if the collection already exists or can be created.
example: createCollection
my $subcoll = "$supercoll/$myname";
my ($rc, $success) = $db->createCollection($subcoll);
$rc==0 or die "$rc $success";
$obj->describeCollection([COLLECTION], OPTIONS)
Returns the RC and a HASH with details. The details are the same as returned with XML::eXistDB::RPC subroutine getCollectionDescr, excluding details about documents.
Option --Default
documents <false>
. documents => BOOLEAN
example:
my ($rc, $descr) = $db->describeCollection($coll, documents => 1);
$rc and die $rc;
print Dumper $descr; # Data::Dumper::Dumper
$obj->listResources([COLLECTION])
[non-API] Returns ... with all documents in the COLLECTION. Without COLLECTION, it will list all documents in the whole repository.
example:
my ($rc, @elems) = $db->listResources;
$rc==0 or die "error: $elems[0] ($rc)";
$obj->moveCollection(FROM, TO | (TOCOLL, SUBCOLL))
Copy the FROM collection to a new TO. With three arguments, SUBCOLL is a collection within TOCOLL.
example:
my ($rc, $succ) = $db->moveCollection('/db/from', '/db/some/to');
my ($rc, $succ) = $db->moveCollection('/db/from', '/db/some', 'to');
$obj->reindexCollection(COLLECTION)
Reindex all documents in a certain collection.
example:
my ($rc, $success) = $db->reindexCollection($name);
die "error: $success ($rc)" if $rc;
die "failed" unless $success;
$obj->removeCollection(COLLECTION)
Remove an entire collection from the database.
example:
my ($rc, $success) = $db->removeCollection($name);
die "error: $rc $success" if $rc;
die "failed" unless $success;
$obj->subCollections([COLLECTION])
[non-API] Returns a list of sub-collections for this collection, based on the results of describeCollection(). The returned names are made absolute.
example:
my ($rc, @subs) = $db->subCollections($coll);
$rc and die "$rc $subs[0]";
print "@subs\n";
Permissions
$obj->describeCollectionPermissions([COLLECTION])
Returns the RC and a HASH which shows the permissions on the COLLECTION. The output of the API is regorously rewritten to simplify implementation.
The HASH contains absolute collection names as keys, and then as values a HASH with user
, group
and mode
.
$obj->describeResourcePermissions(RESOURCE)
[non-API] returns HASH with permission details about a RESOURCE>
$obj->describeUser(USERNAME)
[non-API] returns a HASH with user information.
example:
my ($rc, $user) = $db->describeUser('guest');
$rc==0 or die "error: $user ($rc)";
my @groups = @{$user->{groups}};
$obj->listDocumentPermissions([COLLECTION])
List the permissions for all resources in the COLLECTION
$obj->listGroups
[non-API] list all defined groups. Returns a vector.
example:
my ($rc, @groups) = $db->listGroups;
$rc==0 or die "$groups[0] ($rc)";
$obj->listUsers
[non-API] Returns a LIST with all defined usernames.
example:
my ($rc, @users) = $db->listUsers;
$rc==0 or die "error $users[0] ($rc)";
$obj->login(USERNAME, [PASSWORD])
[non-API] Change the USERNAME (as known by ExistDB). When you specify a non-existing USERNAME or a wrong PASSWORD, you will not get more data from this connection. The next request will tell.
$obj->removeUser(USERNAME)
Returns true on success.
$obj->setPermissions(TARGET, PERMISSIONS, [USER, GROUP])
The TARGET which is addressed is either a resource or a collection.
The PERMISSIONS are specified either as an integer value or using a modification string. The bit encoding of the integer value corresponds to Unix conventions (with 'x' is replaced by 'update'). The modification string has as syntax: [user|group|other]=[+|-][read|write|update][, ...]
$obj->setUser(USER, PASSWORD, GROUPS, [HOME])
Modifies or creates a repository user. The PASSWORD is plain-text password. GROUPS are specified as single scalar or and ARRAY. The first group is the user's primary group.
Resources
$obj->copyResource(FROM, TOCOLL, TONAME)
example:
my ($rc, $success) = $db->copyResource(...);
$obj->countResources([COLLECTION])
[non-API] Returns the number of resources in the COLLECTION.
example:
my ($rc, $count) = $db->countResources($collection);
$obj->describeResource(RESOURCE)
Returns details about a RESOURCE (which is a document or a binary).
example:
my ($rc, $details) = $db->describeResource($resource);
$obj->lockResource(RESOURCE, [USERNAME])
$obj->moveResource(FROM, TOCOLL, TONAME)
example:
my ($rc, $success) = $db->moveResource(...);
$obj->removeResource(DOCNAME)
[non-API] remove a DOCument from the repository by NAME. This method's name is more consistent than the official API name XML::eXistDB::RPC subroutine remove.
$obj->typeOfResource(RESOURCE)
[non-API] Returns a HASH with details about the RESOURCE.
$obj->uniqueResourceName([COLLECTION])
Produces a random (and hopefully unique) resource-id (string) within the COLLECTION. The returned id looks something like fe7c6ea4.xml
.
example:
my ($rc, $id) = $db->uniqueResourceName($coll);
$obj->unlockResource(RESOURCE)
Returns its success.
$obj->whoLockedResource(RESOURCE)
[non-API] Returns a username.
Download documents
$obj->downloadDocument(RESOURCE, FORMAT)
Returns a document as byte array.
$obj->listResourceTimestamps(RESOURCE)
[non-API] Returns the creation and modification dates.
example:
my ($rc, $created, $modified) = $db->listResourceTimestamps($resource);
$rc==0 or die "error: $created ($rc)";
Upload documents
$obj->downloadBinary(RESOURCE)
[non-API] Get the bytes of a binary file from the server.
example:
my ($rc, $bytes) = $db->downloadBinary($resource);
$obj->uploadBinary(RESOURCE, BYTES, MIME, REPLACE, [CREATED, MODIFIED])
[non-API] The BYTES can be passed as string or better as string reference.
example:
my ($rc, $ok) = $db->storeBinaryResource($name, $bytes, 'text/html', 1);
$obj->uploadDocument(RESOURCE, DOCUMENT, OPTIONS)
[non-API] Hide all the different kinds of uploads via parse() or upload() behind one interface.
It depends on the size of the document and the type of DATA provided, whether upload(), uploadCompressed, or parse() is used to transmit the data to the server.
Option --Default
beautify <false>
chunk_size <new(chunk_size)>
compress <new(compress_upload)>
creation_date <undef>
is_xml <false>
mime_type 'text/xml'
modify_date <undef>
replace <false>
. beautify => BOOLEAN
. chunk_size => KILOBYTES
. compress => KILOBYTES
. creation_date => DATE
. is_xml => BOOLEAN # treatAsXML
. mime_type => STRING
. modify_date => DATE
. replace => BOOLEAN
Queries
Compiled queries
$obj->compile(QUERY, FORMAT)
Returns a HASH.
$obj->describeCompile(QUERY, FORMAT)
[non-API] Returns a string which contains the diagnostics of compiling the query.
$obj->execute(QUERYHANDLE, FORMAT)
Returns a HASH.
Query returns resultset
$obj->describeResultSet(RESULTSET)
[non-API] Retrieve a summary of the result set identified by it's result-set-id. This method returns a HASH with simple values queryTime
(milli-seconds) and hits
(number of results). Besides, it contains complex structures documents
and doctypes
.
$obj->executeQuery(QUERY, [ENCODING], [FORMAT])
example:
my $resultid = $db->executeQuery($query);
$db->releaseResults($resultid);
$obj->numberOfResults(RESULTSET)
[non-API] Returns the number of answers in the RESULT set of a query. Replaces XML::eXistDB::RPC subroutine getHits.
$obj->releaseResultSet(RESULTSET, [PARAMS])
[non-API] Give-up on the RESULTSET on the server.
$obj->retrieveResult(RESULTSET, POS, [FORMAT])
[non-API] retrieve a single result from the RESULT-SET. Replaces retrieve() and retrieveFirstChunk().
$obj->retrieveResults(RESULTSET, [FORMAT])
Replaces retrieveAll() and retrieveAllFirstChunk().
Single return query
$obj->query(QUERY, LIMIT, [FIRST], [FORMAT])
[deprecated according to the java description] Returns a document of the collected results.
Simple node queries
$obj->retrieveDocumentNode(DOCUMENT, NODEID, [FORMAT])
[non-API] Collect one node from a certain document. Doesn't matter how large: this method will always work (by always using chunks).
Modify document content
$obj->updateCollection(COLLECTION, XUPDATE)
[non-API]
example:
my ($rc, $some_int) = $db->updateCollection($coll, $xupdate);
$obj->updateResource(RESOURCE, XUPDATE, [ENCODING])
example:
my ($rc, $some_int) = $db->updateResource($resource, $xupdate);
Indexing
$obj->getIndexedElements(COLLECTION, RECURSIVE)
$obj->scanIndexTerms(COLLECTION, BEGIN, END, RECURSIVE)
or $db->scanIndexTerms(XPATH, BEGIN, END)
.
example:
my ($rc, $details) = $db->scanIndexTerms($xpath, $begin, $end);
my ($rc, $details) = $db->scanIndexTerms($coll, $begin, $end, $recurse);
Helpers
Please avoid
Some standard API methods have gotten more powerful alternatives. Please avoid using the methods described in this section (although they do work)
#-----------------
Please avoid: collections
$obj->getCollectionDesc([COLLECTION])
Please use describeCollection() with option documents = 0
.
Please avoid: download documents
$obj->getDocument(RESOURCE, FORMAT|(ENCODING, PRETTY, STYLE))
Please use downloadDocument(). Either specify FORMAT parameters (a list of pairs), or three arguments. In the latter case, the STYLE must be present but may be undef
.
$obj->getDocumentAsString(RESOURCE, FORMAT|(ENCODING, PRETTY, STYLE))
Please use downloadDocument(). See getDocument().
$obj->getDocumentData(RESOURCE, FORMAT)
Please use downloadDocument(). Retrieve the specified document, but limit the number of bytes transmitted to avoid memory shortage on the server. The size of the chunks is controled by the server. Returned is a HASH.
When the returned HASH contains supports-long-offset
, then get the next Chunk with getNextExtendedChunk() otherwise use getNextChunk().
example:
my ($rc, $chunk) = $db->getDocumentData($resource);
my $doc = $chunk->{data};
while($rc==0 && $chunk->{offset}!=0)
{ ($rc, $chunk) = $chunk->{'supports-long-offset'}
? $db->getNextExtendedChunk($chunk->{handle}, $chunk->{offset})
: $db->getNextChunk($chunk->{handle}, $chunk->{offset});
$rc==0 and $doc .= $chunk->{data};
}
$rc==0 or die "error: $chunk ($rc)";
$obj->getNextChunk(TMPNAME, OFFSET)
Collect the next chunk, initiated with a getDocumentData(). The file is limited to 2GB.
$obj->getNextExtendedChunk(TMPNAME, OFFSET)
Collect the next chunk, initiated with a getDocumentData(). This method can only be used with servers which run an eXist which supports long files.
Please avoid: uploading documents
$obj->parse(DOCUMENT, RESOURCE, [REPLACE, [CREATED, MODIFIED]])
Please use uploadDocument(). Store the DOCUMENT of a document under the RESOURCE name into the repository. When REPLACE is true, it will overwrite an existing document when it exists.
The DATA can be a string containing XML or XML::LibXML::Document.
$obj->parseLocal(TEMPNAME, RESOURCE, REPLACE, MIME, [CREATED, MODIFIED])
Please use uploadDocument(). Put the content of document which was just oploaded to the server under some TEMPNAME (received from upload()), as RESOURCE in the database.
NB: Local means "server local", which is remote for us as clients.
$obj->parseLocalExt(TEMPNAME, RESOURCE, REPLACE, MIME, ISXML, [CREATED, MODIFIED])
Please use uploadDocument(). Put the content of document which was just oploaded with upload() to the server under some TEMPNAME (received from upload()) as RESOURCE in the database. Like parseLocal(), but with extra ISXML
boolean, to indicate that the object is XML, where the server does not know that from the mime-type.
NB: Local means "server local", which is remote for us as clients.
$obj->storeBinary(BYTES, RESOURCE, MIME, REPLACE, [CREATED, MODIFIED])
Please use uploadBinary().
$obj->upload([TEMPNAME], CHUNK)
Please use uploadDocument(). Upload a document in parts to the server. The first upload will give you the TEMPoraryNAME for the object. You may leave that name out or explicitly state undef
at that first call. When all data is uploaded, call parseLocal() or parseLocalExt().
example:
my ($rc1, $tmp) = $db->upload(undef, substr($data, 0, 999));
my ($rc2, undef) = $db->upload($tmp, substr($data, 1000));
my ($rc3, $ok) = $db->parseLocal($tmp, '/db/file.xml', 0, 'text/xml')
if $rc1==0 && $rc2==0;
$obj->uploadCompressed([TEMPNAME], CHUNK)
Please use uploadDocument(). Like upload(), although the chunks are part of a compressed file.
Please avoid: simple node queries
$obj->retrieveFirstChunk((DOCUMENT, NODEID)|(RESULTSET, POS), [FORMAT])
Please use retrieveDocumentNode() or retrieveResult(). Two very different uses for this method: either retrieve the first part of a single node from a document, or retrieve the first part of an answer in a result set. See getNextChunk() for the next chunks.
Please avoid: collect query results
$obj->retrieve((DOCUMENT, NODEID)|(RESULTSET, POS), [FORMAT])
Please use retrieveResult() or retrieveDocumentNode().
$obj->retrieveAll(RESULTSET, [FORMAT])
Please use retrieveResults().
$obj->retrieveAllFirstChunk(RESULTSET, [FORMAT])
Please use retrieveResults().
Renamed methods
Quite a number of API methods have been renamed to be more consistent with other names. Using the new names should improve readibility.
createResourceId => uniqueResourceName
getBinaryResource => downloadBinary
getCreationDate => collectionCreationDate
getDocType => typeOfResource
getDocumentListing => listResources
getGroups => listGroups
getHits => numberOfResults
getPermissions => describeResourcePermissions
getResourceCount => countResources
getTimestamps => listResourceTimestamps
getUser => describeUser
getUsers => listUsers
hasUserLock => whoLockedResource
listCollectionPermissions => describeCollectionPermissions
printDiagnostics => describeCompile
querySummary => describeResultSet
releaseQueryResult => releaseResultSet
remove => removeResource
xupdate => xupdateCollection
xupdateResource => xupdateResource
Methods with unknown purpose
For all the next methods, it is unclear what they do, or some it their required parameters behave. Please help me documenting them, and I will implement (and probably rename) them.
boolean isValid NAME
boolean dataBackup DESTINATION
List getDocumentChunk(String name, HashMap parameters)
byte[] getDocumentChunk(String name, int start, int stop)
boolean setDocType(String documentName, String doctypename
, String publicid, String systemid)
HashMap queryP(byte[] xpath, HashMap parameters)
HashMap queryP(byte[] xpath, String docName, String s_id
, HashMap parameters)
retrieveAsString(String doc, String id, HashMap parameters)
SEE ALSO
This module is part of XML-ExistDB distribution version 0.09, built on November 25, 2009. Website: http://perl.overmeer.net/xml-compile/
All modules in this suite: XML::Compile, XML::Compile::SOAP, XML::Compile::SOAP12, XML::Compile::SOAP::Daemon, XML::Compile::Tester, XML::Compile::Cache, XML::Compile::Dumper, XML::Compile::RPC, and XML::Rewrite, XML::ExistDB, XML::LibXML::Simple.
Please post questions or ideas to the mailinglist at http://lists.scsys.co.uk/cgi-bin/mailman/listinfo/xml-compile For life contact with other developers, visit the #xml-compile
channel on irc.perl.org
.
LICENSE
Copyrights 2009 by Mark Overmeer. For other contributors see ChangeLog.
This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself. See http://www.perl.com/perl/misc/Artistic.html