Quick links: Tutorial - Examples - Files - Symbols.
Classes: Hierarchy - Index - List - Members.
Namespaces: Index - base - cs - display.
Cette page est disponible en français.

Client-server architecture

This section describes the client-server architecture of the library.

The client-server architecture of Cogitant makes available objects handled by the library (support, graphs, rules) and operations (input / output, projection searches, rule applications, checkouts, etc.) to other applications, possibly run on other workstations. Uses of this client / server architecture can be divided into two categories:

In both cases, the server can be used as a support(s) and base(s) graphs server (graph storage and operation execution). In this section, we describe as a first step the compilation and installation procedure. In a second step we describe more precisely the classes of the client/server architecture. Finally, in the latter part, the exchange protocol is described, in the form of the format DTD.

Introduction

A Cogitant server (called TCP server from now) may be queried by clients through a TCP connection (connected mode), or a message exchange following the HTTP protocol (each request makes a connection that is stopped after receiving the reply), as illustrated in Figure 1. In the first case, clients communicate directly with the TCP server. In the second case, clients communicate with a HTTP server (Apache http://www.apache.org for example), this HTTP server transmits its orders to the HTTP/TCP interfacing module of Cogitant, which is itself in communication with a TCP server. The interfacing module communicates with the TCP server through TCP, and it is therefore possible to install the TCP server on another machine (A) that the one used for the HTTP server (B). In this way, it is possible to install the TCP server on a machine only visible on a local area network (and invisible from the Internet), and to make this server (indirectly) available (to C, D, E and F) through a HTTP server, provided that the HTTP server machine, on which is executed the HTTP/TCP interfacing module, can access through TCP to the machine on which the TCP server is executed. HTTP/TCP interfacing is done through a CGI, which receives (by the POST protocol) data from the client. If you did not understand the preceding sentences, take an aspirin, and reread them, otherwise, an go on.

archi_cs.png

Figure 1. Different methods for accessing the server.

Compilation

The library must be compiled with specific options so that client/server features are available. Exchanges between clients and server (exchange of XML messages, see Exchange protocol) can be done in different ways, but for now, the only exchange possibilities are the use of TCP or HTTP protocol. Exchange messages at the physical level (sockets) can be done in different ways, but for now, TCP and HTTP exchanges have been developed using the GNU Common C++ library (http://www.gnu.org/software/commoncpp). This library is a Free Software, offers a number of features that are not present in the C++ standard library. Nevertheless, it is not provided with standard compilers of the market. It is therefore required to download the source (http://www.gnutelephony.org/dist/tarballs/) and to compile it before being able to compile client/server functions of Cogitant. Note that in most GNU/Linux distributions, this library is available as a package. If you are in this case, it is not required to compile Common C++ from source, simply install the corresponding package as well as the development package (libcommonc++ and libcommonc++-dev under Debian). Common C++ has been tested with Cogitant under Linux and Windows with version 1.7.3.

Under Unix

We assume the Common C++ library is installed ahead. To check this, simply type ccgnu-config –version in a shell, the command must be recognized, and something like 1.9.7 should be displayed. If you are using version 2 of Common C++, you must use ccgnu2-config –version . To compile Cogitant with client/server functions, you have to pass the –enable-cs to the configure script. As client/server functions can be developed with a library other than Common C++ (this is not the case now), it should be noted that the compiling will be done using the library, for this, you have to add the option –with-ccxx. In the end, the call to the configure script must have this form:

./configure --enable-cs --with-ccxx2

After the configuration process, just launch the compiling in the usual way.

Under Windows, with Visual C++ 2008

Note that using Borland C++ (recommended method in the 5.1.x versions of Cogitant) can not be used, it is now necessary to use Visual C++ to use the client-server architecture of Cogitant.

The first thing to do is the compiling of Common C ++ with Visual C ++. To do that, first download the sources of the library, and extract the contents of the archive. Thereafter, we assume that the archive has been extracted in D:\commoncpp2-1.x.x. Open the project D:\commoncpp2-1.x.x\w32\vs2008\ccgnu2.vcproj. Ensure that Visual C++ generate files in Release mode (abd not in Debug mode) and launch the compiling. Once the compiling is finished D:\commoncpp2-1.x.x\w32\vs2008\Release contains the two dynamic libraries (CapeCommon17.dll and CapeExtras17.dll, but this may vary depending on the version of Common C++).

No it is time to configure Cogitant, in the usual way, with CMake. Launch CMake on the Cogitant directory and, after selecting file generation for Visual C++ 2008, check WithClientServer_CommonCPP. Click on Configure. An error occurs, but it is quite normal: you must choose in CcppBaseDir the directory that contains Common C++, in our example D:\commoncpp2-1.x.x. CcppLibraryDir (directory that contains Common C++ dlls)should be set automatically after a Configure and also CcppLibraries (names of Common C++ dlls, without "dll" suffix). If not, change the values of these variables. Click on Generate and open the project in Visual C++ to start the compiling.

Examples

To check that the library has been properly compiled with the client/server features enable, the easiest way is to run the example of server and client. The server is samples/doc/server_1[.exe] and the client is in test/client. Both programs are compiled by default (at the make time) under Unix, and must be compiled (in the usual way) under Windows. Run the server, then launch the client. This client is testing the server by sending it a large number of requests by TCP. Under Windows, make sure dynamic libraries (dll) required for the execution of these programmes are in search paths: cogitant.dll (if Cogitant was compiled in dll), Common C++ dlls, and runtime libraries from the compiler. For this, you can copy the these dll into directories containing executables, or change the value of PATH so that it contains directories containing dlls in question.

You can connect to the server by using the telnet application. To do so, execute the command telnet 127.0.0.1 4246 (4246 is the port used by the default server). You can then enter queries respecting the Exchange protocol. The server response is displayed in return.

Installing the TCP server

No installation is required. You just have to compile the server. The server code (server_1.cpp) is very simple, it merely instanciates classes of the library. The only important point lies in the choice of operations that are offered to clients. So you can build a server precisely providing the operations you want to provide (and prohibit others, for example, you prohibit the clients to load a new support, or to load graphs, etc.). By taking inspiration from the source of the default server, you can also build a server providing new operations, for this you just have to define new subclasses of cogitantcs::OpeServer and to make these operations available to the server.

Installation of the server module usable through HTTP

The use of the HTTP protocol is recommended when the Cogitant server has to be available via the Internet. Indeed, in the case of using HTTP, you just have to install the interfacing module HTTP/TCP to make it known by the HTTP server (Apache, etc.), and in this way, the Cogitant server is accessible through the HTTP server, like any Web page. Thus, messages can pass through a firewall (as the port 80 used by the HTTP service is not usually filtered), and there is no need to "open" a new port to pass messages as would ask the TCP server.

To make the Cogitant server accessible via HTTP, it is therefore required to install the CGI of TCP/HTTP interfacing on the machine running the HTTP server. CGIs are often written in script languages (it would be possible to use such a script here), but the interfacing module is written in C++, even if its code is very simple: it merely "redirects" the request (received by POST) to the TCP server (by default, it forwards the request on the TCP server running on the same machine, but you just have to modify the source (cgtserver_cgi.cpp) to redirect the request to a TCP server of another machine). The source of this CGI resides in the directory samples/cgiserver.

In this directory, there is also a file query.html which can be used to send a request to a server Cogitant from a browser. To use this html page, the cgi must be executable by the HTTP server in the same directory (see below).

Configuring Apache

Execution and test

Start the TCP server (in samples/doc), by typing server_1. It is then possible to load the test page in a browser (http://127.0.0.1/cogitant/query.html). If you do not see the page, you badly configured the alias (thought about restarting apache?) or the link.
The execution of a request should provoke a response (or an error if the request does not match the dtd cogitantcs.dtd, but not an error of type unknownserver, indicating that the HTTP/TCP interfacing module did not find the TCP server). Note that the server is expected to communicate with clients which respect the DTD, and that therefore, if incorrect request are sent to the server, this can lead to strange behaviors or even a server freeze. Note that most browsers (Mozilla, IE, etc.) do not display XML documents in the usual area, and that one must choose the source display to see the server response. You can also use the test client application, located in test/client and called client, which communicates with the server by TCP or HTTP. You can use parameters passed to the program to specify a machine name, a port number, the use of the HTTP protocol and the URL (syntaxe : client [http] [http://<host>[:<port>]/<dir>/cgtserver.cgi] [tcp [<host_tcp>[<port_tcp>]]]).

Programming

Classes enabling exchange between server and client are all in the namespace cogitantcs. They enable to use remote (on the server) supports, graphs and rules as if they were local (on the client). Once a distant object is needed on the client, a request is sent by the client, and the server returns it characteristics of this object. See examples (samples/doc/server_*.cpp) and documentation of classes in the namespace cogitantcs for more information.

Programming the server

The server management is provided by the class cogitantcs::Server. This class manages the receipt of client messages, the execution of requests and the sending of replies. Each server is associated with a set of cogitant::Environment, and this is the content of these environments (support, graphs and rules as well as the corresponding operations) which is offered to clients. To adapt a server to different uses, it is possible to customize certain aspects of the server, like operations available and offered to the server and the mode of receipt and sending.

In general, the server execution is launched by instantiating cogitantcs::Server (or a subclass, see below), calling the method cogitantcs::Server::addStdOperations() or cogitantcs::Server::addMinOperations(), and finally calling cogitantcs::Server::mainLoop().

// server_1.cpp
// To be able to test this program, the current directory must be "samples/doc"
// as all the names of the BCGCT files are given relatively to this directory.
#include <iostream>
int main(int, char* [])
{
server.addStdOperations();
try
{
server.mainLoop();
}
catch (cogitant::Exception & e)
{
std::cerr << e << std::endl;
}
return 0;
}

The method addStdOperations() can launch a server that offers all standard operations provided with the library, while the method addMinOperations() creates a server that merely offers minimal operations, i.e. those for accessing (read only) supports and graphs of the server. In the latter case, clients cannot modify the provided data, it is therefore necessary, before calling mainLoop(), to build one (or more) environment. To do this, simply initialize an environment in the usual way, then add this environment to the server by calling cogitantcs::Server::addEnvironment() (see example below).

// server_init.cpp
// To be able to test this program, the current directory must be "samples"
// as all the names of the BCGCT files are given relatively to this directory.
#include <iostream>
using namespace std;
int main(int, char* [])
{
try
{
env->readSupport("bcgct/bucolic/bucolic.bcs");
env->readGraphs("bcgct/bucolic/sleepandfish.bcg");
}
catch (cogitant::Exception const & e)
{
cerr << e;
return 1;
}
server.addStdOperations();
server.addEnvironment(env, "env_bucolic");
server.mainLoop();
return 0;
}

In most cases, it is necessary to add new operations to servers, for example, specific operations for questioning of a graph, or specific operations of input output. Such operations are not part of the "standard" protocol of Cogitant but can be used by a "specific" client to query a "specific" server. Like any Cogitant operations, such operations must be subclasses of cogitant::OperationBase. Actually, server operations must be subclasses of cogitantcs::OpeServer. By using this mechanism, it is not necessary to write a subclass of Server to add new operations, just write a subclass of OpeServer corresponding to the desired operation, instantiate this class, and add this instance to the server using the method cogitantcs::Server::addOperation(). In this way, adding new operations, or modifying existing operations is simplified, and can even be done dynamically, during the execution of the server. To define a new operation it is therefore necessary to define a subclass of cogitantcs::OpeServer. More precisely, it is necessary to redefine two methods in the subclass to be created:

While it is possible to customize the functioning of a server by adding new operations, it is also possible to customize it by using special functions of XML messages transport. Indeed, depending on the application, communication between client and server can be done in different ways. Cogitant comes with a server that can be questioned through a TCP connection (with Common C++) and a client can connect to the server via a TCP or HTTP connection (still with Common C++). It is possible to add new transport methods, for example to use libraries different from Common C++ or by directly "tackling" the sockets layer of the operating system, or to use other communication methods that enable transporting XML documents (such as pipes, or name pipes). Adding new transport methods is very easy, because transport operations are not part of the server or the client, but are deported in the abstract class cogitantcs::OperationCSIO (client server input output). To any server and to any client is associated with an instance of a subclass of cogitantcs::OperationCSIO. And each time the client or the server must send data, receive data, or pending connections, it calls methods on this instance of OperationCSIO). So, to define new methods of information transport, just define a subclass of cogitantcs::OperationCSIO and more precisely redefine the following methods:

For example, cogitantcs::OperationCSIO_Simple provides input output operations from C++ flows. The constructor of this class takes two parameters: a ostream and a istream. Using this input output operation, you can for example use a server on cout and cin, pass requests on the standard input, and retrieve results on the standard output. However this operation is not cannot be used for real communication with a client. For real connections, on can use the class cogitantcs::OperationCSIO_TCP which use Common C++ to provide inputs/outputs on TCP. This class is provided with two constructors cogitantcs::OperationCSIO_TCP::OperationCSIO_TCP(), the first only takes an integer parameter, and should be used to instantiate the operation to be used in a server. The integer is thus the waiting port number of the server. The second constructor takes two parameters: a string and an integer. The second has to be used in a client. The first will be the server name to which the client will connect, and the second parameter the port number. To use a specific class of transport, simply instantiate the chosen class, and pass a pointer to this instance to the constructor of cogitantcs::Server or cogitantcs::Client. It is possible to do the same thing more simply, by using the class cogitantcs::Server_TCP whose constructor only takes a parameter, the waiting port number (see the example above). Note however that the use of Server_TCP is merely a shortcut and is exactly equivalent to instantiating cogitantcs::OperationCSIO_TCP and pass the created instance to the constructor cogitantcs::Server::Server().

Client programming

The client (cogitantcs::Client) can be used in different ways, more or less simple and allow access to more or less features.

Of course, these three use modes correspond to a single method of communication with the server, the exchange of XML messages using the transport layer.

As in the case of a server, the transport of XML messages is carried out by a subclass of cogitantcs::OperationCSIO. The Client constructor takes as a parameter a pointer to an instance of a subclass of OperationCSIO. However, in order to ease the use of a TCP client, the class cogitantcs::Client_TCP is defined, and its constructor takes two parameters: the hostname on which the server is executed, and the waiting port number of the server. Similarly, the class cogitantcs::Client_HTTP allows you to simply connect to a server via HTTP. The constructor of this class only takes a single parameter, a string which should contain the URL of the interfacing CGI.

To use a client, one should not instantiate the class cogitant::Environment, because the client requires the use of specific data structures. These classes (cogitantcs::SetClient and its subclasses, cogitantcs::EnvironmentAllocatorClient) provide sets (of types, of graphs) which query the server as soon as a required element is unknown to the client. So, when a client connects to a server, it does not transfer the whole support and graphs, but objects are transferred as soon as necessary. One sould not instantiate Environment, but rather the method cogitantcs::Client::environment() which returns (a pointer to) the environment managed by the client. But this environment cannot be used from the connection to the server. Indeed, a server can handle multiple environments, it is therefore necessary to select which of its environnements is chosen by the client. This is done thanks to the method cogitantcs::Client::setServerEnvironment(). This method is overloaded: it may take as a parameter an integer (server-side environment number, i.e. the result of cogitantcs::Server::addEnvironment()) or a string (name of the environment , i.e. the string passed as a second parameter to cogitantcs::Server::addEnvironment()). So the example below connects to a server and selects the environment named env_bucolic.

// To use with server_init
#include <iostream>
int main(int , char* [])
{
cogitantcs::Client_TCP client("127.0.0.1", 4246);
client.setServerEnvironment("env_bucolic");
cogitant::Environment * env = client.environment();
std::cout << *(env->support()) << std::endl;
env->writeGraph(std::cout, 0);
return 0;
}

As can be seen from this example, once the client is initialized, it is possible to access objects in the environment in the usual way. Thus, the execution of this programme (whose result is given below) displays the support and the first graph (in the linear format), the same way as if this support and this graph were "locally" loaded.

cogitant::Support
 ConceptTypes : 0:Universal, 1:Action, 2:Attribute, 3:Boat, 4:Bucolic, 5:Couple,
 6:Entity, 7:Fish, 8:Lake, 9:Living being, 10:Painting, 11:Person, 12:Place, 13:
Scene, 14:Sleep, 15:Think
 PartialOrder : (0 (1, 2, 6)) (1 (15, 14, 7)) (2 (4)) (3 ()) (4 ()) (5 ()) (6 (1
3, 5, 3, 12, 10, 9)) (7 ()) (8 ()) (9 (11, 7)) (10 ()) (11 ()) (12 (8)) (13 ())
(14 ()) (15 ())
 RelationTypes : 0:agent, 1:attr, 2:in, 3:object, 4:on
 PartialOrder : (0 ()) (1 ()) (2 ()) (3 ()) (4 ())
 NestingTypes : 0:Description, 1:Component, 2:Representation
 PartialOrder : (0 (1, 2)) (1 ()) (2 ())
 Individuals : 0:Peter(11), 1:A(10)

sleepandfish:
        [Person:Peter]<-(agent)<-[Sleep]
        [Person]<-(agent)<-[Fish]->(in)->[Lake].

Once an access will be done on an environment object which is not present in the client, a request will be automatically generated towards the server, which return the object description to the client. The client environment is therefore an image of the server environment, this image can be incomplete as some objects have not (yet) been transferred. This has a consequence, however: it is forbidden to add or delete objects in the client environment, because in this case, the client environment would no longer be an image of the server. Moreover, in the case where several clients are connected to the same server, it would be very difficult and costly to maintain consistency between all environments. That is why automatic transfers are done in a server to client direction, and the server environment is evidence.

However, in some cases, it may be necessary, from a client, to modify server objects (modifying an existing graph, adding or deleting a graph, loading a support, etc.). For such uses, the class cogitantcs::Client contains methods like cogitantcs::Client::newEnvironmentObject() that can change the server environment (and thus, indirectly, the client environment). It is then possible to access functions that are not available from the environment. For example, if a client-side graph is changed, these changes are not sent to the server because made they are done onto the local copy. By using the method cogitantcs::Client::commitEnvironmentObject(), it is possible to transfer modifications to the server. The corresponding sever-side graph is then changed, provided that the server accepts modifications from clients. Such a modification of the server environment is not automatic: it is necessary to explicitly call this method. So, concurrence issues (updating a single object by two clients connected to the same server for example) are the responsibility of the programmer. Refer to the documentation of cogitantcs::Client to know all methods interacting with the server.

In some cases, it is better to have no mechanism for automatic updates, and to explicitely make all updates, whether in one way or another. Among other drawbacks of the automatic update, graphs have the same identifier (iSet) in the server and the client, which prevents to create new ones or to destroy some in the client (except via methods of access to the server, which may in some cases become weighty). In the case where the client only needs a few graphs, it may be easier to disable the automatic update, to retrieve some graphs from the server (which have in the client an identifier which may be different from their identifier in the server), to create some locally or load some from a local file, then to send some of these graphs the server to make it perform certain processings. It is possible to disable automatic updates separately for the support and for environment objects. This requires using the two last parameters of the constructor of cogitantcs::Client (and its sub-classes, like cogitantcs::Client_TCP::Client_TCP()), as described in the two examples below.

Example. The example below creates a client in which support and graphs are different from those handled by the server. In this way, the client can modify "its" support (by loading a file using cogitant::Environment::readSupport:()) and send the support got from the server (cogitantcs::Client::commitSupport()). On the server side, the environment created for the occasion (cogitantcs::Client::newEnvironment()) receives the server sent by the client. To check it, a second client is created and chooses the environment previously created on the server. So by displaying the support associated with this customer, we get the support that was sent by the first client.

// A utiliser avec server_1
#include <iostream>
int main(int , char* [])
{
try
{
cogitantcs::Client_TCP client("127.0.0.1", 4246, true, true);
cogitant::iSet ne = client.newEnvironment();
client.setServerEnvironment(ne);
client.environment()->readSupport("bcgct/sisyphus/sisyphus.bcs");
client.commitSupport();
client.close();
cogitantcs::Client_TCP client2("127.0.0.1", 4246);
client2.setServerEnvironment(ne);
cogitant::Environment * env = client2.environment();
std::cout << *(env->support()) << std::endl;
}
catch (cogitant::Exception const & e)
{
std::cout << e << std::endl;
}
return 0;
}

Example. The second example illustrates the use of a support obtained from the server, and graphs (and rules) local to the client. Here, the client load (locally) a graph and a rule, and sends these two objects to the server (cogitantcs::Client::commitEnvironmentObject()), after obtaining two identifiers from the server to store these two objects (cogitantcs::Client::newEnvironmentObject()). The graph loaded from the client and sent to the server is then stored on the server side (cogitantcs::Client::saveEnvironmentObject()). The second client enables to check the result of operations of the first: the graph and the rule are available on the server.

// To use with server_1
#include <iostream>
int main(int , char* [])
{
// Distant support; local graphs and rules
cogitantcs::Client_TCP client("127.0.0.1", 4246, false, true);
cogitant::iSet ne = client.newEnvironment();
client.loadSupport("bcgct/sisyphus/sisyphus.bcs", ne);
client.setServerEnvironment(ne);
cogitant::Environment * env = client.environment();
cogitant::iSet igraph = env->readGraphs("bcgct/sisyphus/locals.bcg");
cogitant::iSet irule = env->readGraphs("bcgct/sisyphus/near_1.bcr");
cogitant::iSet igraph_server = client.newEnvironmentObject();
client.commitEnvironmentObject(igraph, igraph_server);
client.saveEnvironmentObject("tmp.bcg", igraph_server);
cogitant::iSet irule_server = client.newEnvironmentObject();
client.commitEnvironmentObject(irule, irule_server);
client.close();
// A new client tries to access objects of the same environment
cogitantcs::Client_TCP client2("127.0.0.1", 4246);
client2.setServerEnvironment(ne);
env = client2.environment();
std::cout << *(env->graphs(igraph_server)) << std::endl;
std::cout << *(env->rules(irule_server)) << std::endl;
return 0;
}

Finally, the third mode of exchange with the server is to explicitely generate an request in the form of an XML document. Indeed, methods of cogitantcs::Client cover only "standards" messages of Cogitant. If new operations are defined in the server, it is necessary to send specific messages. To do this, you can use cogitantcs::Client::addPendingQuery() which adds to the "pending" XML document an operation execution tag and cogitantcs::Client::answer() which returns the XML response received from the server.

It is also possible to send XML messages from an application that is not based on Cogitant, for example to use functions offered by a server from a Java application. The example below, to be used in conjunction with the server server_1, can create an environment, load a graph and send it to the client from a java client which merely sends and receive XML messages.

// To use with server_init
import java.net.Socket;
import java.io.PrintStream;
import java.io.BufferedReader;
import java.io.IOException;
import java.util.Vector;
public class SimpleClient
{
private Socket m_socket;
private PrintStream m_os;
private BufferedReader m_is;
boolean m_trace;
public SimpleClient() throws IOException
{
m_socket = new Socket("127.0.0.1", 4246);
m_os = new PrintStream(m_socket.getOutputStream());
m_is = new BufferedReader(new java.io.InputStreamReader(m_socket.getInputStream()));
m_trace = true;
}
// Send the request and return the answer of the server
public Vector sendQuery(String q) throws IOException
{
m_os.println("<?xml version=\"1.0\" encoding=\"iso-8859-1\" standalone=\"no\"?>");
m_os.println("<!DOCTYPE cogitantquery SYSTEM cogitantcs.dtd>");
m_os.println("<cogitantquery requiresheader=\"0\">");
m_os.println("\t<" + q + "/>");
m_os.println("</cogitantquery>");
if (m_trace)
System.out.println("--> " + q);
return getAnswer();
}
// Reading the server response
public Vector getAnswer() throws IOException
{
Vector v = new Vector();
String tmp;
do
{
tmp = m_is.readLine();
v.add(tmp);
} while (! tmp.equals("</cogitantanswer>"));
// The end of a cogitantanswer message is marked by a EOF character,
// which is passed to the next call to read()
m_is.read();
if (m_trace)
{
System.out.println("<-- " + v.get(0));
for (int i=1; i<v.size(); i++)
System.out.println(" " + v.get(i));
}
return v;
}
public static void main(String args[]) throws IOException
{
SimpleClient sc = new SimpleClient();
System.out.println("*** Querying the number of available environments on the server");
sc.sendQuery("qserver");
System.out.println("*** Creating a new environment");
sc.sendQuery("qnewenvironment");
// We should retrieve the identifier of the environment created
// from the server answer (in analysing the XML tags received).
// Here, we assume that it is 0.
int idenv = 0;
System.out.println("*** Loading a support");
sc.sendQuery("qloadsupport env=\"" + idenv + "\" file=\"bcgct/bucolic/bucolic.bcs\"");
System.out.println("*** Loading a graph");
sc.sendQuery("qloadgraphs env=\"" + idenv + "\" file=\"bcgct/bucolic/simplequery.bcg\"");
// We should retrieve the identifier of the read graph.
// Here, we assume that it is 0.
int idgra = 0;
System.out.println("*** Downloading this graph");
sc.sendQuery("qenvironmentobject env=\"" + idenv + "\" id=\"" + idgra + "\"");
System.out.println("*** Deleting the environment");
sc.sendQuery("qdeleteenvironment env=\"0\"");
}
};

The above example is very simplied, as responses received from the server are not analysed, and are displayed as they are on the screen. However, there are a large number of Java libraries that can parse XML, and by using them, you can easily interpret server responses, to determine whether the graph was correctly loaded, what are the vertices that form the graph and to build a representation "local to the client" of the graph, and so on.

Exchange protocol

Exchanges between server and client are done though XML messages. The following DTD documents messages that can be sent by the client and by the server. The client can only send documents having a tag cogitantquery as a root, and the server documents having cogitantanswer as a root.

<?xml version="1.0" encoding="UTF-8"?>

<!--

DTD CogitantCS 1.3

This DTD describes the exchange protocol between a Cogitant server and its
clients.

To apply this DTD, use the following syntax:
<!DOCTYPE cogitantquery PUBLIC "-//COGITANT//Cogitant Client-server Specification 1.3//EN" "http://cogitant.sourceforge.net/cogitantcs.dtd">
or
<!DOCTYPE cogitantanswer PUBLIC "-//COGITANT//Cogitant Client-server Specification 1.3//EN" "http://cogitant.sourceforge.net/cogitantcs.dtd">

This file is part of Cogitant which is a library facilitating construction of
applications using conceptual graphs.  It is under GPL licence.
http://cogitant.sourceforge.net
Cogitant version 5.2.0 - Last change of the DTD : 21/05/2009

-->


<!-- Extensions des attributs des balises standard. -->

<!ENTITY % cogitantQueryExtensions "">
<!ENTITY % cogitantAnswerExtensions "">


<!-- Document. -->

<!ELEMENT cogitantquery (qserver | qenvironment | qsetcontent | qconcepttype |
	qrelationtype | qnestingtype | qindividual | qenvironmentobject | qgraph |
	qrule | qcommitenvironmentobject | qcommitimmediateless | qcomparison |
	qimmediateless | qimmediategreater | qbannedobjects | qgraphobject
	qnewenvironment | qnewenvironmentobject | qloadsupport | qsavesupport |
	qloadgraphs | qsaveenvironmentobjects | qdeleteenvironment |
	qdeleteenvironmentobject | qnewsupportobject | qcommitsupportobject |
	qprojections | qruleapplications | qruleapply | qrulesclosure |
	qconstraintsatisfaction |
	qcopyenvironmentobject |
	qoperationconfig |
	qaddconcept | qaddrelation | qaddnesting | qdelgraphobject |
	qaddedge | qdeledge |
	%cogitantQueryExtensions; )*>
	<!-- reguiresheader : si égal à 0, le serveur n'envoie pas une entête
		destinée au serveur http (Content-type: ... Cet attribut doit donc être
		utilisé (avec la valeur 0) quand le serveur est utilisé en accès direct
		(TCP) pour ne pas recevoir ce header. -->
<!ATTLIST cogitantquery
	requiresheader CDATA '1'
>

<!ELEMENT cogitantanswer (server | environment | setcontent | concepttype |
	relationtype | nestingtype | individual | environmentobject | graph | rule |
	deletedobject | commitenvironmentobject | commitimmediateless | comparison |
	immediateless | immediategreater | bannedobjects | graphobject
	newenvironment | newenvironmentobject | loadsupport |
	loadgraphs | saveenvironmentobjects | deleteenvironment |
	deleteenvironmentobject | newsupportobject | commitsupportobject |
	projections | ruleapplications | ruleapply | rulesclosure |
	constraintsatisfaction |
	copyenvironmentobject |
	operationconfig |
	addconcept | addrelation | addnesting | delgraphobject |
	addedge | deledge |
	error %cogitantAnswerExtensions;)*>
<!ATTLIST cogitantanswer
>

<!ELEMENT error EMPTY>
<!ATTLIST error
	<!-- syntax : syntaxe xml non respectée dans le message requête.
		 environmentid : identificateur d'environnement inconnu (attribut env).
		 setid : identificateur d'ensemble inconnu (attribut set).
		 objectid : identificateur d'objet inconnu (par ex, dans un graphe, une
		  arête a pour extrémité un objet qui n'existe pas).
		 objecttype : l'identificateur d'objet se réfère à un objet du mauvais
		  type (par ex, vérification d'une contrainte avec l'id d'un objet de l'
		  environnement qui n'est pas une contrainte.
		 unknownserver : retourné par cgiserver quand il n'arrive pas à établir
		  une connexion avec le serveur TCP.
		 arg : contient un descriptif plus détailé de l'erreur (parfois). -->
	type (syntax | environmentid | setid | objectid | objecttype | unknownserver) #REQUIRED
	arg CDATA #IMPLIED
>

<!-- Propriétés d'un objet -->
<!ELEMENT properties (property*)>
	<!-- subid : Identificateur de sous-ensemble de propriétés. Si absent,
		l'élément prop désigne l'ensemble principal. -->
<!ATTLIST properties
	subid CDATA #IMPLIED
>

<!ELEMENT property EMPTY>
<!ATTLIST property
	type CDATA #IMPLIED
	value CDATA #IMPLIED
>

<!-- A partir de la DTD 1.3, certains attributs d'objets ne sont plus transférés comme
	des propriétés mais des attributs. Les attributs correspondent à des informations
	faisant partie du modèle (conformité d'un type de relation, par exemple), alors que
	les propriétés représentent des informations externes au modèle (position d'un sommet,
	par exemple). -->
<!ELEMENT attribute EMPTY>
<!ATTLIST attribute
	type CDATA #IMPLIED
	value CDATA #IMPLIED
>


<!-- Identificateur d'un objet de l'environnement. -->
<!ELEMENT eoid EMPTY>
<!ATTLIST eoid
	id CDATA #REQUIRED
>


<!-- Serveur. -->

<!ELEMENT qserver EMPTY>
<!ATTLIST qserver>

<!ELEMENT server (properties*)>
	<!-- environments : Nombre d'environnements disponibles sur le serveur -->
<!ATTLIST server
	environments CDATA #REQUIRED
>

<!-- Environnement. -->

<!ELEMENT qenvironment EMPTY>
	<!-- env (numéro de l'environnement) ou name doivent être donnés. -->
<!ATTLIST qenvironment
	env CDATA #IMPLIED
	name CDATA #IMPLIED
>

<!ELEMENT environment (properties*, support)>
	<!-- objects : Taille de l'ensemble d'EnvironmentObjects -->
<!ATTLIST environment
	env CDATA #REQUIRED
	objects CDATA #REQUIRED
	name CDATA #IMPLIED
>

<!ELEMENT support (properties*)>
	<!-- xxxtypes : Tailles des ensembles du support -->
<!ATTLIST support
	concepttypes CDATA #REQUIRED
	relationtypes CDATA #REQUIRED
	nestingtypes CDATA #REQUIRED
	individuals CDATA #REQUIRED
	bannedtypes CDATA #REQUIRED
>

<!-- Contenu d'un ensemble (de TC, de TR, de TN, de MI, de EnvironmentObject). -->

<!ELEMENT qsetcontent EMPTY>
	<!-- set : Numéro de l'ensemble = numéro de l'environnement * 10 +1 (TC)
		+2 (TR) +3 (TN) +4 (MI) +5 (EnvironmentObjects).
		 id : Identificateur dans l'ensemble de l'élément demandé ou "all" :
		tout le contenu de l'ensemble. -->
<!ATTLIST qsetcontent
	set CDATA #REQUIRED
	id CDATA #REQUIRED
>

<!-- Type de concept. -->

<!ELEMENT qconcepttype EMPTY>
	<!-- env : Numéro de l'environnement. (idem relationtype, nestingtype,
		individual, environmentobject)
		 id : Numéro dans l'ensemble de l'objet demandé ou "all" (tout le
		contenu de l'ensemble). (idem relationtype, nestingtype, individual,
		environmentobject) -->
<!ATTLIST qconcepttype
	env CDATA #REQUIRED
	id CDATA #REQUIRED
>

<!ELEMENT concepttype (attribute*, properties*)>
<!ATTLIST concepttype
	set CDATA #REQUIRED
	id CDATA #REQUIRED
>

<!-- Type de relation. -->

<!ELEMENT qrelationtype EMPTY>
<!ATTLIST qrelationtype
	env CDATA #REQUIRED
	id CDATA #REQUIRED
>

<!ELEMENT relationtype (attribute*, properties*)>
<!ATTLIST relationtype
	set CDATA #REQUIRED
	id CDATA #REQUIRED
>

<!-- Type d'emboîtement. -->

<!ELEMENT qnestingtype EMPTY>
<!ATTLIST qnestingtype
	env CDATA #REQUIRED
	id CDATA #REQUIRED
>

<!ELEMENT nestingtype (attribute*, properties*)>
<!ATTLIST nestingtype
	set CDATA #REQUIRED
	id CDATA #REQUIRED
>

<!-- Marqueur individuel. -->

<!ELEMENT qindividual EMPTY>
<!ATTLIST qindividual
	env CDATA #REQUIRED
	id CDATA #REQUIRED
>

<!ELEMENT individual (attribute*, properties*)>
<!ATTLIST individual
	set CDATA #REQUIRED
	id CDATA #REQUIRED
>

<!-- Élément de l'environnement. -->

<!ELEMENT qenvironmentobject EMPTY>
	<!-- env : Numéro de l'environnement côté serveur.
		 id : Numéro de l'objet dans l'environnement ou "all".
		 iddest : Numéro d'identifiant chez le client. N'est précisé que dans
		le cas où il est différent d'id. La valeur de cet attribut est
		simplement recopiée telle quelle par le serveur dans la réponse, et
		peut être utilisée par le client. Cet attribut ne doit pas être utilisé
		dans le cas ou id vaut "all". -->
<!ATTLIST qenvironmentobject
	env CDATA #REQUIRED
	id CDATA #REQUIRED
	iddest CDATA #IMPLIED
>

<!ELEMENT deletedobject EMPTY>
<!ATTLIST deletedobject
	set CDATA #REQUIRED
	id CDATA #REQUIRED
>

<!-- Graphe. -->

<!ELEMENT qgraph EMPTY>
	<!-- cf. environmentobject -->
<!ATTLIST qgraph
	env CDATA #REQUIRED
	id CDATA #REQUIRED
	iddest CDATA #IMPLIED
>

<!ELEMENT graph (properties*, (internalgraph | concept | relation | nesting | coreferenceclass)*)>
	<!-- size : Taille de l'ensemble de noeuds.
		 set, id : sont obligatoires quand le graphe est transféré en tant
		qu'objet de l'environment, sont interdits quand le graphe est
		transféré à l'intérieur d'une règle. -->
<!ATTLIST graph
	set CDATA #IMPLIED
	id CDATA #IMPLIED
	iddest CDATA #IMPLIED
	size CDATA #REQUIRED
>

<!ELEMENT internalgraph (properties*, edge*)>
<!ATTLIST internalgraph
	id CDATA #REQUIRED
>
<!ELEMENT concept (properties*, edge*)>
<!ATTLIST concept
	id CDATA #REQUIRED
>
<!ELEMENT relation (properties*, edge*)>
<!ATTLIST relation
	id CDATA #REQUIRED
>
<!ELEMENT nesting (properties*, edge*)>
<!ATTLIST nesting
	id CDATA #REQUIRED
>
<!ELEMENT coreferenceclass (properties*, edge*)>
<!ATTLIST coreferenceclass
	id CDATA #REQUIRED
>
	<!-- Attention, l'ordre des arêtes liées à un noeud d'un graphe est
		important, et doit être transféré "tel quel". -->
<!ELEMENT edge EMPTY>
	<!-- env : Extrémité de l'arête (identificateur de sommet, ou * pour
		ISET_NULL)
		 label : Étiquette de l'arête (entier (étiquette de l'arête) ou 'P'
		(lien parent) 'C' (lien enfant) ou '=' (lien de coreference). -->
<!ATTLIST edge
	end CDATA #REQUIRED
	label CDATA #REQUIRED
>

<!-- Règle. -->

<!ELEMENT qrule EMPTY>
	<!-- cf. environmentobject -->
<!ATTLIST qrule
	env CDATA #REQUIRED
	id CDATA #REQUIRED
	iddest CDATA #IMPLIED
>

<!ELEMENT rule (properties*, hypothesis, conclusion, conpt*)>
<!ATTLIST rule
	set CDATA #IMPLIED
	id CDATA #REQUIRED
	iddest CDATA #IMPLIED
>
<!ELEMENT hypothesis (graph)>
<!ATTLIST hypothesis>
<!ELEMENT conclusion (graph)>
<!ATTLIST conclusion>
<!ELEMENT conpt EMPTY>
<!ATTLIST conpt
	idc1 CDATA #REQUIRED
	idc2 CDATA #REQUIRED
>

<!-- Transfert d'un objet de l'environnement du client vers le serveur. -->

<!ELEMENT qcommitenvironmentobject (graph | rule)>
<!ATTLIST qcommitenvironmentobject
	env CDATA #REQUIRED
>

<!ELEMENT commitenvironmentobject EMPTY>
<!ATTLIST commitenvironmentobject 
	error CDATA #IMPLIED>


<!-- Accès aux plus petits immédiats d'un type. -->

<!ELEMENT qcommitimmediateless (qilid*)>
	<!-- tp= "c": type de concept, "r": type de relation, "n": type d'emboîtement -->
<!ATTLIST qcommitimmediateless
	env CDATA #REQUIRED
	tp CDATA #REQUIRED
>

<!ELEMENT qilid EMPTY>
	<!-- id1 > id2
		 setunset= "s" fixer id1 > id2, "u" supprimer id1 > id2 -->
<!ATTLIST qilid
	id1 CDATA #REQUIRED
	id2 CDATA #REQUIRED
	setunset CDATA 's'
>

<!ELEMENT qcommitimmediateless>
<!ATTLIST qcommitimmediateless
	error CDATA #IMPLIED>


<!-- Comparaison de deux types. -->

<!ELEMENT qcomparison EMPTY>
	<!-- set : Numéro de l'ensemble = numéro de l'environnement * 10 +1 (TC)
		+2 (TR) +3 (TN). -->
<!ATTLIST qcomparison
	set CDATA #REQUIRED
	id1 CDATA #REQUIRED
	id2 CDATA #REQUIRED
>

<!ELEMENT comparison EMPTY>
<!ATTLIST comparison
	set CDATA #REQUIRED
	id1 CDATA #REQUIRED
	id2 CDATA #REQUIRED
	result CDATA #REQUIRED
>

<!-- Accès aux plus petits immédiats d'un type. -->

<!ELEMENT qimmediateless EMPTY>
	<!-- set : Numéro de l'ensemble = numéro de l'environnement * 10 +1 (TC)
		+2 (TR) +3 (TN).
		 id : identificateur du type ou "all". -->
<!ATTLIST qimmediateless
	set CDATA #REQUIRED
	id CDATA #REQUIRED
>

<!ELEMENT immediateless (ilid*)>
<!ATTLIST immediateless
	set CDATA #REQUIRED
	id CDATA #REQUIRED
>
<!ELEMENT ilid EMPTY>
<!ATTLIST ilid
	id CDATA #REQUIRED
>

<!-- Accès aux plus grands immédiats d'un type. -->

<!ELEMENT qimmediategreater EMPTY>
	<!-- set : Numéro de l'ensemble = numéro de l'environnement * 10 +1 (TC)
		+2 (TR) +3 (TN).
		 id : identificateur du type ou "all". -->
<!ATTLIST qimmediategrater
	set CDATA #REQUIRED
	id CDATA #REQUIRED
>

<!ELEMENT immediategreater (igid*)>
<!ATTLIST immediategreater
	set CDATA #REQUIRED
	id CDATA #REQUIRED
>
<!ELEMENT igid EMPTY>
<!ATTLIST igid
	id CDATA #REQUIRED
>

<!-- Accès aux types interdits. -->

<!ELEMENT qbannedtypes EMPTY>
	<!-- env : identificateur de l'environnement à interroger. -->
<!ATTLIST qbannedtypes
	env CDATA #REQUIRED>

<!ELEMENT bannedtypes (bannedtype*)>
<!ATTLIST bannedtypes
	env CDATA #REQUIRED>
	<!-- L'élément bannedtypes contient autant d'éléments bannedtype qu'il y a
	de types interdits. -->
<!ELEMENT bannedtype (btid*)>
	<!-- Chaque élément bannedtype contient des éléments btid pour chaque
	identificateur de type primitif composant le type conjonctif interdit. -->
<!ELEMENT btid EMPTY>
<!ATTLIST btid
	id CDATA #REQUIRED
>

<!-- Accès à un objet (concept, relation, graphe interne, emboîtement, classe
de coref) composant un graphe. -->

<!ELEMENT qgraphobject EMPTY>
	<!-- env : Numéro de l'environnement côté serveur.
	     idgraph : Identificateur du graphe.
		 idobject : Identificateur de l'objet l'intérieur du graphe. -->
<!ATTLIST qgraphobject
	env CDATA #REQUIRED
	idgraph CDATA #REQUIRED
	idobject CDATA #IMPLIED
>
<!ELEMENT graphobject (internalgraph | concept | relation | nesting | coreferenceclass)>
<!ATTLIST graphobject
	env CDATA #REQUIRED
	idgraph CDATA #REQUIRED
>

<!-- Création d'un nouvel environnement. -->

<!ELEMENT qnewenvironment EMPTY>
<!ATTLIST qnewenvironment
	<!-- Optimisation automatique de l'ordre partiel des types de concepts. Par
	défaut, oui. Attention, s'il est optimisé, il ne doit plus être modifié.
	-->
	optorderc CDATA "true"
	<!-- Idem, sur les types de relations. -->
	optorderr CDATA "true"
	<!-- Idem, sur les types d'emboîtements. -->
	optordern CDATA "true"
	<!-- Optimisation automatique pour la recherche rapide de types de concepts
	par leur intitulé. -->
	optlabelc CDATA "true"
	<!-- Idem, sur les types de relations. -->
	optlabelr CDATA "true"
	<!-- Idem, sur les types d'emboîtements. -->
	optlabeln CDATA "true"
	<!-- Idem, sur les marqueurs individuels. -->
	optlabeli CDATA "true"
>

<!ELEMENT newenvironment EMPTY>
<!ATTLIST newenvironment
	env CDATA #REQUIRED
>

<!-- Création d'un nouvel objet dans l'environnement. -->

<!ELEMENT qnewenvironmentobject EMPTY>
	<!-- tp= "g": graphe (par défaut), "r": règle, "p": contrainte positive,
	"n": contrainte négative. -->
<!ATTLIST qnewenvironmentobject
	env CDATA #REQUIRED
	tp (g | r | p | n) "g"
>

<!ELEMENT newenvironmentobject EMPTY>
<!ATTLIST newenvironemntobject
	id CDATA #REQUIRED
>

<!-- Chargement d'un support. -->

	<!-- Le support peut être chargé à partir d'un fichier disponible sur
l'hote serveur, en utilisant l'attribut file. Le support peut aussi être
transféré à partir du client. Dans ce cas, l'attribut file ne doit pas être
donné, et l'attribut embedded doit valoir "bcgct" ou "cogxml" ou "cgif". La balise
qloadsupport doit alors avoir comme fils le texte bcgct ou cogxml du support.
-->
<!ELEMENT qloadsupport (#PCDATA)>
<!ATTLIST qloadsupport
	env CDATA #REQUIRED
	file CDATA #IMPLIED
	embedded CDATA #IMPLIED
>

<!ELEMENT loadsupport EMPTY>
<!ATTLIST loadsupport
	error CDATA #IMPLIED
>

<!-- Sauvegarde du support côté serveur.
 Si l'attribut embedded est passé, il doit valoir "bcgct", "cogxml" ou "cgif".
 Dans ce cas, l'attribut "file" ne doit pas être passé, et le resultat de
 l'écriture dans le format choisi n'est pas enregistré sur disque, mais
 transmis dans la réponse saveenvironmentobjects comme texte emboîté (dans un
 PCDATA). -->

<!ELEMENT qsavesupport EMPTY>
<!ATTLIST qsavesupport
	env CDATA #REQUIRED
	file CDATA #IMPLIED
	embedded CDATA #IMPLIED
>

<!ELEMENT savesupport (#PCDATA)>
<!ATTLIST savesupport
	error CDATA #IMPLIED
>

<!-- Chargement de graphes (ou règles).
 Transfert d'un graphe en PCDATA par utilisation de l'attribut embedded.
-->

<!ELEMENT qloadgraphs (#PCDATA)>
<!ATTLIST qloadgraphs
	env CDATA #REQUIRED
	file CDATA #IMPLIED
	embedded CDATA #IMPLIED
>

<!ELEMENT loadgraphs (loadedgraph*)>
<!ATTLIST loadgraphs
	error CDATA #IMPLIED
>

<!ELEMENT loadedgraph EMPTY>
<!ATTLIST loadedgraph
	id CDATA #REQUIRED
>

<!-- Sauvegarde d'un graphe (ou règle).
 Si l'attribut embedded est passé, il doit valoir "bcgct", "cogxml" ou "cgif".
 Dans ce cas, l'attribut "file" ne doit pas être passé, et le resultat de
 l'écriture dans le format choisi n'est pas enregistré sur disque, mais
 transmis dans la réponse saveenvironmentobjects comme texte emboîté (dans un
 PCDATA). -->

<!ELEMENT qsaveenvironmentobjects (eoid*)>
<!ATTLIST qsaveenvironmentobjects
	env CDATA #REQUIRED
	file CDATA #IMPLIED
	id CDATA #IMPLIED
>

<!ELEMENT saveenvironmentobjects (#PCDATA)>
<!ATTLIST saveenvironmentobjects
	error CDATA #IMPLIED
>

<!-- Destruction d'un environnement. -->

<!ELEMENT qdeleteenvironment EMPTY>
<!ATTLIST qdeleteenvironment
	env CDATA #REQUIRED
>

<!ELEMENT deleteenvironment EMPTY>
<!ATTLIST qdeleteenvironment
>

<!-- Destruction d'un objet de l'environnement -->

<!ELEMENT qdeleteenvironmentobject EMPTY>
<!ATTLIST qdeleteenvironmentobject
	env CDATA #REQUIRED
	id CDATA #REQUIRED
>

<!ELEMENT deleteenvironmentobject EMPTY>
<!ATTLIST deleteenvironmentobject
	error CDATA #IMPLIED
>

<!-- Création d'un nouveau type ou marqueur -->

<!ELEMENT qnewsupportobject EMPTY>
	<!-- tp= "c": type de concept, "r": type de relation, "n": type
	d'emboîtement, "i": marqueur individuel.
	Le label est l'intitulé (optionnel) de l'élément à créer. Si aucun
	intitulé n'est passé, utiliser qcommitsupportobject pour envoyer la
	propriété label. -->
<!ATTLIST qnewsupportobject
	env CDATA #REQUIRED
	tp CDATA #REQUIRED
	label CDATA #IMPLIED
>

<!ELEMENT newsupportobject EMPTY>
<!ATTLIST newsupportobject
	id CDATA #REQUIRED
>

<!-- Transfert d'un objet du support (TC, TR, TN, I) du client vers le serveur. -->

<!ELEMENT qcommitsupportobject (properties*)>
<!ATTLIST qcommitsupportobject 
	env CDATA #REQUIRED
	tp CDATA #REQUIRED
	id CDATA #REQUIRED
>

<!ELEMENT commitsupportobject EMPTY)
<!ATTLIST commitenvironmentobject 
	error CDATA #IMPLIED>
>


<!-- Projection. -->

<!ELEMENT projection (couple*)>
<!ELEMENT couple EMPTY>
<!ATTLIST couple
	id1 CDATA #REQUIRED
	id2 CDATA #REQUIRED
>

<!-- Demande du calcul des projections d'un graphe dans un autre. -->

<!ELEMENT qprojections (projectionconfig?)>
<!ATTLIST qprojections
	env CDATA #REQUIRED
	<!-- id1: graphe projeté. -->
	id1 CDATA #REQUIRED
	<!-- id2: graphe dans lequel on projette. -->
	id2 CDATA #REQUIRED
>

<!ELEMENT projectionconfig EMPTY>
<!ATTLIST projectionconfig
	<!-- Nombre max de projections trouvées. 0 pour ne pas limiter. -->
	maxsize CDATA #IMPLIED 0
	<!-- Si true les projections (ensemble de couples) sont retournées,
	     sinon, seul le nombre est retourné. -->
	memorize CDATA #IMPLIED "true"
>

<!ELEMENT projections (projection*)>
<!ATTLIST projections
	<!-- Le nombre de projections trouvées. -->
	size CDATA #REQUIRED
>

<!-- Demande du calcul des applications d'une règle dans un graphe. -->

<!ELEMENT qruleapplications (projectionconfig?)>
<!ATTLIST qruleapplications
	env CDATA #REQUIRED
	<!-- idr: identificateur de la règle. -->
	idr CDATA #REQUIRED
	<!-- idg: identificateur du graphe. -->
	idg CDATA #REQUIRED
>

<!ELEMENT ruleapplications (projection*)>
<!ATTLIST ruleapplications
	size CDATA #REQUIRED
>

<!-- Application d'une règle sur un graphe selon une projection. -->

<!ELEMENT qruleapply (projection)>
<!ATTLIST qruleapply
	env CDATA #REQUIRED
	idr CDATA #REQUIRED
	idg CDATA #REQUIRED
>

<!ELEMENT ruleapply EMPTY>
<!ATTLIST ruleapply 
	error CDATA #IMPLIED>
>

<!-- Fermeture d'un graphe par un ensemble de règles.-->

	<!-- Les éléments eoid fils de la balise doivent contenir les
	identificateurs des règles à appliquer. Si aucun eoid n'est précisé, toutes
	les règles de l'environnement sont utilisées. -->
<!ELEMENT qrulesclosure (eoid*)>
<!ATTLIST qrulesclosure
	env CDATA #REQUIRED
	<!-- Identificateur du graphe. L'application de l'opération modifie ce
	graphe. -->
	idg CDATA #REQUIRED
	<!-- Nombre maximum d'applications de règles. Par défaut 0, i.e.
	applications illimitées. -->
	maxa CDATA '0'
>

<!ELEMENT rulesclosure EMPTY>
<!ATTLIST rulesclosure 
	error CDATA #IMPLIED
>

<!-- Vérification de la validité d'un graphe par rapport à une contrainte. -->

<!ELEMENT qconstraintsatisfaction>
<!ATTLIST qconstraintsatisfaction
	env CDATA #REQUIRED
	<!-- idr: identificateur de la contrainte. -->
	idc CDATA #REQUIRED
	<!-- idg: identificateur du graphe. -->
	idg CDATA #REQUIRED
>

<!ELEMENT constraintsatisfaction>
<!ATTLIST constraintsatisfaction
	<!-- result: "true" si le graphe vérifie la contrainte, "false" sinon. -->
	result CDATA #REQUIRED
>


<!-- Copie d'un objet de l'environnement (graphe ou règle). -->

<!ELEMENT qcopyenvironmentobject EMPTY>
<!ATTLIST qcopyenvironmentobject
	env CDATA #REQUIRED
	idsrc CDATA #REQUIRED
	iddst CDATA #REQUIRED
>

<!ELEMENT copyenvironmentobject EMPTY>
<!ATTLIST copyenvironmentobject
	error CDATA #IMPLIED
>


<!-- Modification de la configuration d'une opération. -->

<!ELEMENT qoperationconfig EMPTY>
<!ATTLIST qoperationconfig
	env CDATA #REQUIRED
	<!-- ope: opération concernée, param: nom du paramètre à modifier, value: valeur. -->
	<!-- Les valeurs autorisées pour l'instant sont :
	     - ope : iohandler  param : graphobjectidentifiers  value : true | false
		   Si défini à true, l'opération de chargement de graphes conserve dans la propriété
		   Property::IDENTIFIER l'identificateur lu dans le fichier.
	-->
	ope (iohandler) #REQUIRED 
	param (graphobjectidentifiers) #REQUIRED
	value (true | false) #REQUIRED
>

<!ELEMENT operationconfig EMPTY>
<!ATTLIST operationconfig
	error CDATA #IMPLIED
>


<!-- Ajout d'éléments dans un graphe. -->

<!-- Ajout d'un sommet concept dans un graphe. -->

<!ELEMENT qaddconcept>
<!ATTLIST qaddconcept 
	env CDATA #REQUIRED
	<!-- idg : identificateur du graphe. -->
	idg CDATA #REQUIRED
	<!-- idp : identificateur de l'InternalGraph dans lequel le sommet doit
	être créé, 0 par défaut. -->
	idp CDATA "0"
	<!-- idt : type de concept. Il s'agit de l'iSet du type à créer. -->
	idt CDATA #REQUIRED
	<!-- idm : marqueur individuel. Ne pas utiliser cet attribut pour créer
	un sommet concept générique. Si cet attribut est utilisé, il doit contenir
	l'iSet du marqueur. -->
	idm CDATA #IMPLIED
>
<!ELEMENT addconcept EMPTY>
<!ATTLIST addconcept
	<!-- id : identificateur de l'objet créé dans le graphe. -->
	id CDATA #IMPLIED
	error CDATA #IMPLIED
>

<!-- Ajout d'un sommet relation, cf. qaddconcept. -->
<!ELEMENT qaddrelation>
<!ATTLIST qaddrelation 
	env CDATA #REQUIRED
	idg CDATA #REQUIRED
	idp CDATA "0"
	idt CDATA #REQUIRED
>
<!ELEMENT addrelation EMPTY>
<!ATTLIST addrelation
	id CDATA #IMPLIED
	error CDATA #IMPLIED
>

<!-- Ajout d'un emboîtement, cf. qaddconcept. -->
<!ELEMENT qaddnesting>
<!ATTLIST qaddnesting 
	env CDATA #REQUIRED
	idg CDATA #REQUIRED
	idp CDATA #REQUIRED
	idt CDATA #REQUIRED
>
<!ELEMENT addnesting EMPTY>
<!ATTLIST addnesting
	id CDATA #IMPLIED
	error CDATA #IMPLIED
>

<!-- Suppression d'un élément d'un graphe. -->

<!ELEMENT qdelgraphobject>
<!ATTLIST qdelgraphobject
	env CDATA #REQUIRED
	<!-- idg : identificateur du graphe. -->
	idg CDATA #REQUIRED
	<!-- id : identificateur de l'objet à détruire (iSet). -->
	id CDATA #REQUIRED
>
<!ATTLIST delgraphobject EMPTY>
<!ATTLIST delgraphobject
	error CDATA #IMPLIED
>


<!-- Ajout d'une arête au graphe. -->

<!ELEMENT qaddedge EMPTY>
<!ATTLIST qaddedge
	env CDATA #REQUIRED
	<!-- idg : identificateur du graphe. -->
	idg CDATA #REQUIRED
	<!-- idr : identificateur du sommet relation dans le graphe (iSet). -->
	idr CDATA #REQUIRED
	<!-- idr : identificateur du sommet concept dans le graphe (iSet). -->
	idc CDATA #REQUIRED
	<!-- lab : étiquette de l'arête à créer. L'étiquette doit avoir une valeur
	inférieure ou égale à l'arité du type de relation du sommet relation. -->
	lab CDATA #REQUIRED
>
<!ELEMENT addedge EMPTY>
<!ATTLIST addedge
	error CDATA #IMPLIED
>

<!-- Suppression d'une arête d'un graphe. -->

<!ELEMENT qdeledge>
<!ATTLIST qdeledge
	env CDATA #REQUIRED
	<!-- idg : identificateur du graphe. -->
	idg CDATA #REQUIRED
	<!-- idr : identificateur du sommet relation (iSet). -->
	idr CDATA #REQUIRED
	<!-- lab : étiquette de l'arête à supprimer. -->
	lab CDATA #REQUIRED
>
<!ATTLIST deledge EMPTY>
<!ATTLIST deledge
	error CDATA #IMPLIED
>