RQL in a nutshell

RQL is the abbreviation of “RedDot Query Language”. RQL is the programming interface for the Open Text Management Server. Almost all actions that can be executed via the normal frontend (SmartTree, SmartEdit, Server Manager) can also be executed via the interface RQL. This result into the ability to write small (or even bigger) applications that does a specific job consisting of several steps automatically. Technically spoken it is a simple to understand request-response model.

Figure 1:CD cover of an old RQL workshop ;-)
Figure 1: CD cover of an old RQL workshop ūüėČ

History: Before RQL has been implemented as the interface for the application, all actions that lead to any communication with the project database were implemented as SQL statements. As the number of functions increased the number of different SQL statements increased accordingly. When RedDot CMS 4.0 has been released in April 2001 RQL was now part of software and supported efficient development. The guys from R&D didn’t have to know each SQL statement any longer but could just use short RQL statements which were “translated” into SQL statements by the RQL object.

As RQL is not just used within the development department but can also be used by partners and customers, probably hundreds or thousands of applications have been created in the last ten years.

Basic F.A.Q.

Q: What skills do I need in order to create RQL applications?
A: If you do have basic programming knowledge and joined the basic training course for the Open Text Management Server then this should be enough ūüėČ

Q: Is there a specific programming language that I have to use?
A: No, technically spoken every programming language that has the ability to create objects can be used. So C#, ASP, PHP, JSP and many other languages can be used.

Q: Where can I use RQL?
A: You can create plugins that can be called via the normal front end in SmartTree, SmartEdit and in the Server Manager. Further more you can use RQL in the Template code and in external applications.

Q: What cannot be done with RQL?
A: Some functionality in the front end is implemented by using JavaScript and do not result into any communication with the database. As RQL is “just” implemented to communicate with the database, actions that do not require interaction with the database are not handled with RQL.

Hello world!

In this first simple sample we will create a plugin that just lists all pages of the project. (I could have chosen another sample but as (almost) all projects have pages this plugin should work in most cases.)

Step 1: The Plugin target

As plugins do specific things which make sense in a specific context (maybe when someone clicks on a page) we first of all have to decide where the link that calls the plugin shall be displayed. Therefore we click on the item (page, user, whatever) in those context we’d like to provide the plugin and then we click on the info icon above the action menu. In the dialogue that is opened the plugin target is displayed. Highlight the plugin target and paste it into notepad (or any other editor).¬† In SmartEdit the plugin targets can be retrieved via the info icons of all dialogues that provide the ability to insert plugins.

Figure 2: Plugin target
Figure 2: The plugin target for the project start node is displayed

Step 2: Modifying the plugin definition file

Under CMS\ASP\Plugins\ there is a file called sample.xml. This file will contain information (link name, path and name of the plugin, etc.) regarding our plugin.

What we do is:

  1. Under plugins we create a folder called “listpages”
  2. We create a copy of the sample.xml file, rename it to “listpages.xml” and move it to the folder “listpages”
  3. We create a file called listpages.asp (this will be our plugin)
  4. We modify the values of the listpages.xml file as shown below.

Figure 3: Plugin definition file
Figure 3: Plugin definition file

Step 3: Importing the plugin

  1. We enter the Server Manager > Administer plugins > Plugins and click on “Import Plugin” in the action menu.
  2. We browse to the folder “listpages” under “plugins” and choose the listpages.xml file. Then we click on “OK” ….not on “Next” ūüėČ Ready.
  3. After that we have to activate the just imported plugin and assign the plugin to one or more  projects.
Figure 4: Server Manager: Importing the plugin
Figure 4: Server Manager: Importing the plugin

Figure 5: Activate the plugin
Figure 5: Activate the plugin

Step 4: Calling the plugin

After we’ve imported the plugin we can enter the SmartTree mode of the project, click on the project start node and call the plugin. The dialogue below displays the result….an empty page ūüėČ

Figure 6: First result
Figure 6: First result

Step 5: Programming

Just copy the following code into the file “listpages.asp” and call the plugin again….description follows

<%
sLoginGuid = session("LoginGuid")
set RQLObject                  = Server.CreateObject("RDCMSAsp.RdPageData")
RQLObject.XmlServerClassName   = XmlServerClassName
const XmlServerClassName       = "RDCMSServer.XmlServer"
const DhtmlClassName           = "RDCMSAsp.RdPageData"
RQLStatement = "<IODATA loginguid=""" & sLoginGUID & """ sessionkey=""" & sLoginGUID & """>"&_
"<PROJECT>"&_
"<PAGES action=""list""/>"&_
"</PROJECT>"&_
"</IODATA>"
RQLRequest   = RQLObject.ServerExecuteXml(RQLStatement, sError)
if sError>"" then Response.write "Error -> List pages:</BR></BR>"+sError
response.write server.htmlencode(RQLRequest)
%>

In the first line of the code the session variable “LoginGuid” is retrieved. Every RQL statement need this variable as it indicates that the one who sends the statement to the server is logged on to the system.

In the block below the RQL object is created and some classes are assigned. As this block is just required in two different versions you don’t have to care about the classes.

The RQL statement (<PAGES action=””list””/>) is the really important part of the code. When you spend some time playing around with RQL you’ll figure out that the statements look very similar independently from what they do. The reason is very simple. RQL statements are being used to communicate with the project database. And as databases just know the commands insert, delete and modify (and maybe some more ;-)) RQL statements also just reflect the abilities of the database.

In this line “RQLRequest¬†¬† = RQLObject.ServerExecuteXml(RQLStatement, sError)” the content of the variable RQLStatement is being executed by the method ServerExecuteXml of the RQLObject and the answer of the server is written in the variable RQLRequest.

Step 6: Calling the plugin …again

Call the plugin again or refresh the page. The window should then look like the window below.

Figure 7: Server result: List of all pages
Figure 7: Server result: List of all pages

Step 7: Rendering the result

As we can see in figure 7 the server responded but what we retrieved doesn’t look that fancy. Therefore we need one more object.

If we add the line “set XMLDOMPages¬†¬†¬†¬†¬† = Server.CreateObject(“RDCMSAspObj.RdObject”)” to the block where the objects are created we will have an object that is able to render the result (XML).

Step 8: Displaying the result

In order to loop trough the result we…

  1. Load the result (XML) into our object Call XMLDOMPages.LoadXML (RQLRequest)
  2. Jump to the item “PAGES”
  3. Iterate through all item below the PAGES item
Call XMLDOMPages.LoadXML (RQLRequest)
Set Pagelist   = XMLDOMPages.ObjectByQuery ("//PAGES")
for iCounter = 1 to Pagelist.objects.count
   response.write Pagelist.objects(iCounter)("guid") & "<br>"
   response.write Pagelist.objects(iCounter)("id") & "<br>"
   response.write Pagelist.objects(iCounter)("headline") & "<hr>"
next
Figure 8: Result of the complete code
Figure 8: Result of the complete code

Complete code of the Hello World! plugin

<%
sLoginGuid = session("LoginGuid")
set RQLObject                  = Server.CreateObject("RDCMSAsp.RdPageData")
RQLObject.XmlServerClassName   = XmlServerClassName
const XmlServerClassName       = "RDCMSServer.XmlServer"
const DhtmlClassName           = "RDCMSAsp.RdPageData"
set XMLDOMPages                 = Server.CreateObject("RDCMSAspObj.RdObject")
RQLStatement = "<IODATA loginguid=""" & sLoginGUID & """ sessionkey=""" & sLoginGUID & """>"&_
"<PROJECT>"&_
"<PAGES action=""list""/>"&_
"</PROJECT>"&_
"</IODATA>"
RQLRequest   = RQLObject.ServerExecuteXml(RQLStatement, sError)
if sError>"" then Response.write "Error -> List pages:</BR></BR>"+sError
Call XMLDOMPages.LoadXML (RQLRequest)
Set Pagelist   = XMLDOMPages.ObjectByQuery ("//PAGES")
for iCounter = 1 to Pagelist.objects.count
  response.write Pagelist.objects(iCounter)("guid") & "<br>"
 response.write Pagelist.objects(iCounter)("id") & "<br>"
 response.write Pagelist.objects(iCounter)("headline") & "<hr>"
next
%>

As you can see this RQL plugin uses very few commands such as set, if, for, next.

Some further basics for an easy start

Session variables

In order to work correctly most RQL statements require information such as the current language id or the name of the current user or the GUID of the project. Most information can be somehow retrieved by RQL but it’s much easier just to check if the required value is already available as a session variable.

Sample: When a user opens a page in SmartEdit (or clicks on the page in SmartTree), the GUID of the page can be retrieved by the following line:

myPage = session(“PageGuid”)

If I then would like to get the extended page information of this page I can easily create the RQL statement.

Q: Are the session variables always the same?
A: No, depending where the current user is (SmartTree, SmartEdit, Server Manager) some values are different. If the user clicks on a page, the session variable “TreeGuid” contains the GUID of the page. If the user clicks on a group in the Server Manager, the same variable contains the GUID of the group.

Q: Is there a way to get a list of all session variables?
A: Yes, just create a plugin based on the code below. If you call the plugin from different locations you will see which session varaibles are available and what content they have.

<%
   Response.Buffer = true
   if Request("sessionitem") <> "" then _
  Session(Request("sessionitem")) = Request("sessionitemvalue")
%>
<HTML>
 <HEAD>
    <TITLE>Session Variables</TITLE>
</HEAD>
<BODY>
<%   
 Set oIO = Server.CreateObject ("RDCMSAsp.RdPageData")
 oIO.XmlServerClassName = "RDCMSServer.XmlServer"
%>
<table>
 <tr><td><b>Session Variable</b></td><td><b>Value</b></td></tr>
 <%   
 on error resume next
for each oSession in Session.Contents
   Response.write("<tr><td>" & oSession & "</td><td>")
  sSessionString = Session(oSession)
   if UCase(Left(sSessionString, 7)) = "<IODATA" then
      sSessionString = oIO.EncodeXmlData (sSessionString)
   end if
  Response.Write sSessionString & "</td></tr>"
 Next
 %>
</table>
</BODY>
</HTML>

Performance

Please be aware that plugins might decrease the performance of the editorial server. The editorial server architecture has been designed in order to provide an environment for editors and authors. If you write plugins with mass operations (listing all pages > listing all elements of each page > …) then the number of RQL statements which are sent to the server is much higher than usual.

RQL Statements

First of all you should have a look at the RQL documentation that is part of the software package of the Open Text Management Server. Only statements which are part of the official documentation are supported. So if you use anything else…it will probably work but without any guarantee especially for upcoming versions.

If you don’t have any clue which statement is used to perform a specific action then you can have a look at the RDCMS.log file. Every action via the front end results into an RQL statement that can be found in the RDCMS.log. As there are normally a lot of log files I normally do the following:

  1. Go to the dialogue where I’m interested in the corresponding RQL statement…but don’t execute
  2. Delete all log files under \LOG\common\
  3. Execute the action (Click on OK)
  4. Open the log file RDCMS.log It’s almost empty and I can find the RQL statement very easy.

Rendering the server response

In Step 5 I mentioned that the “block” where the objects are created is required in two different versions. The reason for that is that you either get a (big) list of objects (pages, users, groups, language variants,…) as the answer of your request and therefore have to loop through the results or you just have one item and have a slightly different approach to read out the desired values.

Sample for an XML object that have the ability to read out information of just one item:

const XmlDocumentClassName¬†¬†¬†¬†¬†¬†¬†¬†¬†¬†¬†¬†¬†¬† ¬† = “RDCMSXmlDom.RDDocument”
set XmlDomPageGuid                                    = Server.CreateObject(XmlDocumentClassName)

[RQL statement that creates a page]

sPageGUID = XmlDomPageGuid.ChildNodes(“LINK”).ChildNodes(“PAGE”).GetNodeAttribute(“guid”).AttributeValue

For lots of applications (free & commercial) visit www.solutionexchange.info. This is the best place to get ideas. Create plugins and afterwards post them in order to share them with the community ūüėČ

If something is wrong, missing or cannot be understood, please leave a comment!

Advertisements

16 thoughts on “RQL in a nutshell

  1. Hi Manuel! I have some question about using RQL.
    Can i edit images (resize, crop) which are in Asset manager with RQL? I did not find iinformation about editing images in RQL documenatation. But i found some RQL statement in LOG file (as it is written in your article). I’ve tried to employ it but nothing happens, this RQL does not work. Do you have any suggestions? Thanks in advance.

    1. Hi Marina,

      I’ve also had a look in the log file and found the following statement that worked:

      IODATA sessionkey=”ABF8995AC6BD440F8365FB9A80A6E2F6″
      MEDIA loginguid=”ABF8995AC6BD440F8365FB9A80A6E2F6″
      FOLDER guid=”85DD698B34944C08A0A005C1E76E1CED”
      FILE action=”crop” sourcename=”1logo.png” target=”cropped_2.png” top=”8,1″ size=”150,15″
      FOLDER
      MEDIA
      IODATA

      I’ve tested it and the statement resulted into the file “cropped_2.png”. So technically spoken there is an RQL statement that can crop images, but you probably have to play around with the attributes top and size.

      Hint: As this RQL statement is not part of the docu it’s not supported.

      Hope that helps!
      Best regards,
      Manuel

      1. Thanks Manuel!
        You helped me a lot! I’ve one more question.
        Is there any way to run plug-in just after some event occured? For example after release of a certain page i need to start my plug-in automatically?
        Cheers,
        Marina

      2. Hi Marina,

        it’s always a pleasure to help ūüėČ

        When you follow the instructions below you should be able to do what you planned to do.

        1)Creating a user defined job in the Server Manager
        a) Go to Server Manager > User defined jobs and click on “Create user defined job” in the action menu
        b) in the upcoming dialogue enter a name for this job
        c) in the next dialogue activate the checkbox “call event controlled” and deactivate the other one
        d) in the next dialogue choose the option “Open URL” and enter the url to your RQL application
        2) Assigning the user defined job in the project
        a) Enter the SmartTree
        b) create a workflow
        c) click on “Page created” and then on “add reaction”
        c) click on “Start job” and choose the user defined job you just created in the Server Manager

        Please be aware of the fact that -if you call an RQL application this way- you don’t have any session variables such as login guid or the session key. So you’ll have to write some RQL code for the login procedure and the validation (= connecting to a project)

        As I assume that you would like to perform some action based on the page that has been released I think you’ll need to retrieve the GUID of this specific page. Therefore just add another action (“Write wokflow XML”) to the same step you added the job. Then an XML file containing the GUID of the page will be written in the file system and you can first read out the GUID of the just released page and then use the GUID within your application.

        Good luck!
        Manuel

  2. Thanks for a very useful article! Hopefully I can put it to use in the near future to create a “Submit to Translation” button for SmartEdit ;^)

    1. Thank’s for the comment. Your idea shouldn’t be a big problem.
      Just write the langugage id of the current language variant into a variable (sCurrentLv = session(“languageid”)) and list the language variants of the project. Then iterate through the language variants and display them -excluding the current language variant- with a radio button. After the user has chosen the target language variant and submitted the form you just need one more RQL statement that puts the page into translation editor. If you should face any issues, just drop me a line.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s