Caché + Java + Flex, or how we did the curriculum management system
In this series of articles we will try to consider in detail the main aspects of using this bundle. We used this combine to implement one of the subproblems of the project to develop an intelligent system for the automated management of educational planning. For a better understanding, it is worth saying a few words about the project itself.
Any minor changes in the curriculum lead to enormous labor costs for its processing and coordination in the university services, so the department heads are reluctant to change them. The aim of the project is to create an agent of the department head who will allow you to create a curriculum and make changes in it so that the user does not feel the burden of the routine work of redesigning the curriculum in the case of certain adjustments.
As planned, an agent who is an assistant and consultant is attached to each participant in the curriculum formation process (for example, the department head). The JADE (Java Agent Development Framework) was chosen as a tool to easily implement such agents and process their behavior .
As a DBMS, Caché was usedInterSystems companies. The DBMS was chosen by us for several reasons. Firstly, this DBMS supports an object approach to accessing data, which greatly facilitates the work (apart from the fact that it allows you to create projections of classes in various languages, but this will be discussed below). Secondly, in this system it is easy to configure access areas for users, which will be useful in the future. And finally, InterSystems strongly supports developers who use their products, and also provides licenses for universities for free .
It was decided to make the system cross-platform, for convenience and mobility in future use. To implement the web-interface of the system, a flex-technology was chosen (expanding the basic capabilities of flash).
As a result, at the first stage of development, a number of tasks were identified, which will be discussed in the future (in fact, we will consider these tasks in this series of articles):
To solve the fourth problem, the GraniteDS framework was chosen, the work with which will be described in more detail in the next article.
As a result, the resulting architecture can be represented as follows:

In addition to the above, a connecting agent is installed on the client, which ensures constant communication with the JADE agent and informs the user about events and messages transmitted by the main agent.
In the first part, we will focus our attention on the interaction of Cache -Java.
Consider a fragment of the structure of the Caché database used for the functioning of the agent of the department head in the multi-agent system of educational planning management (MAS UUP). Stored classes were designed and implemented at Caché Studios.

A fragment of the Caché database for the agent of the department head consists of six stored classes, the main of which is the class of disciplines (cDiscipline), which includes all the necessary characteristics of the discipline for compiling the curriculum. From the above diagram it can be seen that the disciplines are divided into cycles and semesters, which, in turn, are included, together with the disciplines, in the curriculum in a certain direction. Discipline can be basic and incorporate several other disciplines, which is implemented by the Parent relation. The relationship of the discipline with the cControlForm class defines the form of control for the discipline (exam or test). The curriculum also contains a list of changes made to it (cLogs class).
For the subsequent implementation of a bunch of Caché stored classes with application logic in java, usingstandard projection mechanism , classes of java projections were generated. Below is the code for creating a java projection in the Caché class.
As noted, the organization of communication with the Caché database was performed using the java projection mechanism, as well as the libraries supplied with Caché for communication via JDBC.
To facilitate development at this stage, a layer of m-classes was created, which allows you to get rid of the classes of java-projections (c-classes).

Why is this done? The java projection classes for the described system generated by Caché are presented on this diagram as a package of classes “Java c-classes”. The Java m-classes package contains classes, each of which corresponds to a class from the Java c-classes package. Java m-classes repeat only the properties of classes from the c- package, and in addition contain their get () and set () methods. This approach is convenient for constant changes in Caché classes, because after the slightest change in Caché, it is enough to regenerate the Java projection of the required Caché class and then make a replacement (and changing m-classes is much easier than editing the newly created projection). In addition, this approach at this stage helps with the organization of microtransactions. For example, it makes it easy to roll back changes in m-classes, which have not yet been stored in c- (in particular, necessary for the algorithm). And taking into account the fact that Java does not directly support cloning, such microtransactions greatly facilitate the work. In addition, Granite DS for creating ActionScript projections requires some changes to the main class (this will be discussed in the second part of the article), and making such changes to the m-class is easier than partially rewriting the structure of the c-class. Therefore, this approach greatly facilitates the work at the main development stage, while at the optimization stage this solution can be reworked. To create ActionScript projections, Granite DS requires some changes to the main class (this will be discussed in the second part of the article), and making such changes to the m-class is easier than partially rewriting the structure of the c-class. Therefore, this approach greatly facilitates the work at the main development stage, while at the optimization stage this solution can be reworked. To create ActionScript projections, Granite DS requires some changes to the main class (this will be discussed in the second part of the article), and making such changes to the m-class is easier than partially rewriting the structure of the c-class. Therefore, this approach greatly facilitates the work at the main development stage, while at the optimization stage this solution can be reworked.
So, for example, from the point of view of efficiency and memory, this approach does not look very attractive. And in the future, most likely, you will have to move away from it by implementing the Serializable interface in c-classes, which is necessary for Granite DS to work.
The CacheTransform class is the link between the Caché database and java classes. This class implements two ways of working with the Caché database: through JDBC and through java projections. To ensure communication with the database via JDBC, the CacheTransform class implements a database connection function. The implementation of this function uses an object of the Database class supplied in the cachedb library. Below is the code for the database connection function.
The InitCon function accepts the basic connection parameters (port - port number, user - username, pass - password for connecting to Caché), enters them into the corresponding global variables and tries to connect to the database. Upon successful connection, the current parameters are entered into the configuration file by the setParams (port, user, pass) function. Also, it is worth noting that url uses localhost, since the java application itself and the database are located on the same machine and in the future it is worth unifying this function so that it accepts both the address of the machine on which the database is running and the database area (in this example, the area - IKIT).
Next, consider the procedure for reading data from the Caché database. In the CacheTransform class, for each java projection class, a pair of functions is implemented, one of which loads one class object by Id, and the other loads all class objects. Below is given
The example shows that to load one object by Id, the _open function of the java projection class is used, and to load all objects, the openByQuery function of the dbconnection object of the Database class is called, into which the SQL query is passed. It is worth noting that IKIT.cControlForm.% ID returns a collection of objects. Next, the TranformCF method is called in both functions:
As can be seen from the description, this method takes a c-class object and, if successful, returns an m-class object. In particular, this method works with the ControlForm class.
The order of saving data in the Caché database is similar to the loading process and is also implemented in the CacheTransform class. The following is an example to save the data of the cControlForm class.
In the example, the input argument to act of RevTranformCF is either 1 or 0. When act is one, the object of the cControlForm class is loaded from the database; otherwise, a new object of the cControlForm class is created. Next, values are assigned to the attributes of the cControlForm object and the save function is called.
The method call of the object of the CacheTransform class is performed in the UserService class, which implements the IUserService interface, which is used in turn by the ActionScript classes of the web application. More on this link will be discussed in the next part of the article.
Summing up the results of this part of the article, we can say that in our case, working with Cache Java projections greatly facilitated the work, since it allows you to bypass the link "Cache class" - "Data" - "Java class", entrusting the main work with DBMS data. Projections are more convenient from the point of view of OOP, since there is direct work with classes and there is no need to manually create the structure of java classes for data processing. So, for example, instead of SQL queries, often returning data whose type must be known in advance, the get (), set () methods are used to get typed data. Among other things, the regeneration of projection classes when compiling the Cache class eliminates the need to make significant changes to Java classes, which would be observed when using communication through JDBC.
As for the basic structure, at the optimization stage, it will be necessary to unify the functions of reading and writing, as well as move from duplicates to clean projections.
In the next part of the article, we will talk about the general structure of the project that implements Caché-Java - Flex communications, interaction mechanisms, and the tools used for this. The operation of the system itself can be seen here .
Any minor changes in the curriculum lead to enormous labor costs for its processing and coordination in the university services, so the department heads are reluctant to change them. The aim of the project is to create an agent of the department head who will allow you to create a curriculum and make changes in it so that the user does not feel the burden of the routine work of redesigning the curriculum in the case of certain adjustments.
As planned, an agent who is an assistant and consultant is attached to each participant in the curriculum formation process (for example, the department head). The JADE (Java Agent Development Framework) was chosen as a tool to easily implement such agents and process their behavior .
As a DBMS, Caché was usedInterSystems companies. The DBMS was chosen by us for several reasons. Firstly, this DBMS supports an object approach to accessing data, which greatly facilitates the work (apart from the fact that it allows you to create projections of classes in various languages, but this will be discussed below). Secondly, in this system it is easy to configure access areas for users, which will be useful in the future. And finally, InterSystems strongly supports developers who use their products, and also provides licenses for universities for free .
It was decided to make the system cross-platform, for convenience and mobility in future use. To implement the web-interface of the system, a flex-technology was chosen (expanding the basic capabilities of flash).
As a result, at the first stage of development, a number of tasks were identified, which will be discussed in the future (in fact, we will consider these tasks in this series of articles):
- Cache class model development
- implementation of the relationship between Cache and Java
- web interface development
- Java interfacing with a web interface
To solve the fourth problem, the GraniteDS framework was chosen, the work with which will be described in more detail in the next article.
As a result, the resulting architecture can be represented as follows:

In addition to the above, a connecting agent is installed on the client, which ensures constant communication with the JADE agent and informs the user about events and messages transmitted by the main agent.
In the first part, we will focus our attention on the interaction of Cache -Java.
Consider a fragment of the structure of the Caché database used for the functioning of the agent of the department head in the multi-agent system of educational planning management (MAS UUP). Stored classes were designed and implemented at Caché Studios.

A fragment of the Caché database for the agent of the department head consists of six stored classes, the main of which is the class of disciplines (cDiscipline), which includes all the necessary characteristics of the discipline for compiling the curriculum. From the above diagram it can be seen that the disciplines are divided into cycles and semesters, which, in turn, are included, together with the disciplines, in the curriculum in a certain direction. Discipline can be basic and incorporate several other disciplines, which is implemented by the Parent relation. The relationship of the discipline with the cControlForm class defines the form of control for the discipline (exam or test). The curriculum also contains a list of changes made to it (cLogs class).
For the subsequent implementation of a bunch of Caché stored classes with application logic in java, usingstandard projection mechanism , classes of java projections were generated. Below is the code for creating a java projection in the Caché class.
Projection PrjName As %Projection.Java(ROOTDIR = "c:\Out\");
//PrjName – имя проекции, ROOTDIR – путь вывода класса на java
As noted, the organization of communication with the Caché database was performed using the java projection mechanism, as well as the libraries supplied with Caché for communication via JDBC.
To facilitate development at this stage, a layer of m-classes was created, which allows you to get rid of the classes of java-projections (c-classes).

Why is this done? The java projection classes for the described system generated by Caché are presented on this diagram as a package of classes “Java c-classes”. The Java m-classes package contains classes, each of which corresponds to a class from the Java c-classes package. Java m-classes repeat only the properties of classes from the c- package, and in addition contain their get () and set () methods. This approach is convenient for constant changes in Caché classes, because after the slightest change in Caché, it is enough to regenerate the Java projection of the required Caché class and then make a replacement (and changing m-classes is much easier than editing the newly created projection). In addition, this approach at this stage helps with the organization of microtransactions. For example, it makes it easy to roll back changes in m-classes, which have not yet been stored in c- (in particular, necessary for the algorithm). And taking into account the fact that Java does not directly support cloning, such microtransactions greatly facilitate the work. In addition, Granite DS for creating ActionScript projections requires some changes to the main class (this will be discussed in the second part of the article), and making such changes to the m-class is easier than partially rewriting the structure of the c-class. Therefore, this approach greatly facilitates the work at the main development stage, while at the optimization stage this solution can be reworked. To create ActionScript projections, Granite DS requires some changes to the main class (this will be discussed in the second part of the article), and making such changes to the m-class is easier than partially rewriting the structure of the c-class. Therefore, this approach greatly facilitates the work at the main development stage, while at the optimization stage this solution can be reworked. To create ActionScript projections, Granite DS requires some changes to the main class (this will be discussed in the second part of the article), and making such changes to the m-class is easier than partially rewriting the structure of the c-class. Therefore, this approach greatly facilitates the work at the main development stage, while at the optimization stage this solution can be reworked.
So, for example, from the point of view of efficiency and memory, this approach does not look very attractive. And in the future, most likely, you will have to move away from it by implementing the Serializable interface in c-classes, which is necessary for Granite DS to work.
The CacheTransform class is the link between the Caché database and java classes. This class implements two ways of working with the Caché database: through JDBC and through java projections. To ensure communication with the database via JDBC, the CacheTransform class implements a database connection function. The implementation of this function uses an object of the Database class supplied in the cachedb library. Below is the code for the database connection function.
public Boolean InitCon(String port, String user, String pass)
{
try {
username=user;
password=pass;
url="jdbc:Cache://localhost:"+port+"/IKIT";
dbconnection = CacheDatabase.getDatabase(url, username, password);
connect=true;
try{
setParams(port,user,pass);
}catch (IOException er){System.out.println("[Error of IO]: "+er);}
return true;
} catch (CacheException e) {
e.printStackTrace();
return false;
}
}
The InitCon function accepts the basic connection parameters (port - port number, user - username, pass - password for connecting to Caché), enters them into the corresponding global variables and tries to connect to the database. Upon successful connection, the current parameters are entered into the configuration file by the setParams (port, user, pass) function. Also, it is worth noting that url uses localhost, since the java application itself and the database are located on the same machine and in the future it is worth unifying this function so that it accepts both the address of the machine on which the database is running and the database area (in this example, the area - IKIT).
Next, consider the procedure for reading data from the Caché database. In the CacheTransform class, for each java projection class, a pair of functions is implemented, one of which loads one class object by Id, and the other loads all class objects. Below is given
sample code for loading objects of the cControlForm class.
///Функция загрузки одного объекта формы контроля
public mControlForm ReadOneCont(Integer ind)
{
try {
if(connect == true)
{
cControlForm temp = (cControlForm) cControlForm._open(dbconnection, new Id(ind));
return TranformCF(temp);
}
return null;
}
catch (CacheException e) {
e.printStackTrace();
return null;
}
}
///Функция загрузки всех объектов форм контроля
public void ReadAllCont()
{
try {
if(connect == true)
{
ListOfCF.clear();
Iterator k = dbconnection.openByQuery("SELECT
IKIT.cControlForm.%ID FROM IKIT.cControlForm");
while (k.hasNext())
{
ListOfCF.add(TranformCF((cControlForm)k.next()));
}
}
}
catch (CacheException e) {
e.printStackTrace();
}
}
The example shows that to load one object by Id, the _open function of the java projection class is used, and to load all objects, the openByQuery function of the dbconnection object of the Database class is called, into which the SQL query is passed. It is worth noting that IKIT.cControlForm.% ID returns a collection of objects. Next, the TranformCF method is called in both functions:
///Трансформация Формы контроля
public mControlForm TranformCF(cControlForm cur)
{
try{
mControlForm res=new mControlForm();
res.setId(Integer.parseInt(cur.getId().toString()));
if(cur.getZET()!=null) res.setZet(cur.getZET().floatValue());
res.setName(cur.getName());
return res;
}
catch (CacheException e) {
e.printStackTrace();
return null;
}
}
As can be seen from the description, this method takes a c-class object and, if successful, returns an m-class object. In particular, this method works with the ControlForm class.
The order of saving data in the Caché database is similar to the loading process and is also implemented in the CacheTransform class. The following is an example to save the data of the cControlForm class.
cControlForm source code
///Трансформация Формы контроля
public cControlForm RevTranformCF(mControlForm cur, Integer act)
{
try {
cControlForm res = null;
if (act == 1)
{
System.out.println("//MAS: TRY EDIT CF: "+ act.toString() + "\nID:" + cur.getId().toString());
res = (cControlForm) cControlForm._open(dbconnection, new Id(cur.getId()));
}
else {
System.out.println("//MAS: TRY ADD CF");
res = new cControlForm(dbconnection);
}
res.setName(cur.getName());
if(cur.getZet() != null) res.setZET(cur.getZet().doubleValue());
res._save();
return res;
}
catch (CacheException e) {
e.printStackTrace(); //To change body of catch statement use File | Settings | File Templates.
return null;
}
}
In the example, the input argument to act of RevTranformCF is either 1 or 0. When act is one, the object of the cControlForm class is loaded from the database; otherwise, a new object of the cControlForm class is created. Next, values are assigned to the attributes of the cControlForm object and the save function is called.
The method call of the object of the CacheTransform class is performed in the UserService class, which implements the IUserService interface, which is used in turn by the ActionScript classes of the web application. More on this link will be discussed in the next part of the article.
Summing up the results of this part of the article, we can say that in our case, working with Cache Java projections greatly facilitated the work, since it allows you to bypass the link "Cache class" - "Data" - "Java class", entrusting the main work with DBMS data. Projections are more convenient from the point of view of OOP, since there is direct work with classes and there is no need to manually create the structure of java classes for data processing. So, for example, instead of SQL queries, often returning data whose type must be known in advance, the get (), set () methods are used to get typed data. Among other things, the regeneration of projection classes when compiling the Cache class eliminates the need to make significant changes to Java classes, which would be observed when using communication through JDBC.
As for the basic structure, at the optimization stage, it will be necessary to unify the functions of reading and writing, as well as move from duplicates to clean projections.
In the next part of the article, we will talk about the general structure of the project that implements Caché-Java - Flex communications, interaction mechanisms, and the tools used for this. The operation of the system itself can be seen here .