written by Manuel Schnitger, 26. January 2011
Even after studying this fascinating article (RQL in a nutshell) of a brilliant developer and talented writer ;) you’ll soon have questions which are not answered in the formerly mentioned article. Therefore I write down some hints that might help you when creating RQL-based applications.
Normally an RQL plugin is called via a link in SmartEdit or SmartTree and will be executed in the second you click on the link…..so user interaction is required. But what has to be done if you want the plugin/application to be executed when a specific event (e.g.: page released) in the workflow is reached? Let’s do it step-by-step.
In this sample the goal is that you trigger an RQL application via the workflow. The action that is performed is not important….just the steps that result into performing the action.
Figure 1:Server Manager - Administer user defined jobs
Figure #2: Add a name for the job
Figure 3: Activating the option "Event controlled"
Figure 4: Adding the URL of your application
Figure 5: Small sample workflow
Figure 6: Workflow triggers a user defined job (RQL application)
Ready!!! Now the RQL application will be triggerred each time a page that is connected to this specific list is being released.
Normally when you wish to start a job when a specific step in the workflow is reached you also want to let the RQL application do something with the page in workflow. But how do you know the GUID of the page in the workflow? And how can you transfer the GUID of the page into your application? It’s very simple. Just add another reaction to the workflow! Click on the action “page released” then on “add reation” in the action menu and choose the reaction “Write workflow XML“. You’ll be asked for a location (folder) where the workflow xml file(s) shall be placed (see figure below) after closing the dialogue every time a page is released two things happen. First the workflow xml file will be written (one file for each page & event) under the specified path and after that the RQL application is triggered. What you then have to do in your application is: Reading out the page guid and using it in your application.
Figure 7: Path for the workflow xml files
Sample code how to extract the GUID of a page and the GUID of the project the page is part of:
Set oXml = Server.CreateObject("Microsoft.XMLDOM") Set rootNode = oXml.documentElement if rootNode.hasChildNodes() Then for Each e in rootNode.childNodes if e.nodename = "PAGEGUID" then sPageGuid = e.childNodes(0).text response.write "<br>PageGuid: " & sPageGuid & "<br>" end if if e.nodename = "PROJECTGUID" then sProjectGuid = e.childNodes(0).text response.write "<br>ProjectGuid: " & sProjectGuid & "<br>" end if next end if
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). (If you should face issues with these steps… leave a comment.)
If you want to delete something using RQL you write something like <PAGE action=”delete” or <USER action=”delete” or something similar depending on the thing you wish to delete. This works well whenever you want to delete the “object” itself; it does not work when you’d like to delete the content (Text) of an object (Textelement). In order to delete a text from a text element or from a standardfield you have to save the so called “Empty buffer”. (Of course the empty buffer can delete much more than just the content of a text element or standardfield.)
Sample for deleting the text of a text element:
sValue = session("EmptyBuffer") "<IODATA format=""1"" loginguid=""" & sLoginGUID & """ sessionkey=""" & sSessionKey & """>"&_ "<ELT reddotcacheguid="""" action=""save"" guid=""" & sEltGuid & """ pageid="""" id="""" index="""" type=""" & sType & """>" & sValue & "</ELT>"&_ "</IODATA>"
Q: What is the empty buffer?
A: It’s just a hash tag followed by the session key of the current user.
So this: response.write session(“emptybuffer”) and this: response.write “#” & session(sessionkey) result in the same output.
Generally plugins or other RQL based applications are placed on the editorial server meaning the server where the Open Text Management Server software is installed. And normally plugins are called via a link or RQL applications are triggered by the workflow. But what if you have a server where a specific application runs and when you want to execute RQL statements triggered by this application?
Sample: There is an application that writes product related information into an XML file and you want to create a page on the editorial server based on this information.
What you could do is a) writing a small directory listener that notices when a new file is being written b) read out the relevant data and c) use the RQL bridge to communicate with the editorial server.
Ok, let’s do it step-by-step
<%@ Language = VBScript %> <%server.ScriptTimeout = 5 %> <% function sendXML(XMLString) set objData = server.CreateObject("RDCMSASP.RdPageData") objData.XmlServerClassName = "RDCMSServer.XmlServer" sendXML = objData.ServerExecuteXml(XMLString, sErrors) end function XMLString = request("sXmlData") if XMLString <> "" then sReturn = sendXML(XMLString) Response.Write sReturn end if %>
As we can see, the function sendXML just executes the RQL statement. The function itself is called in the second block of the code. In the code below we then can see how the communication between the editorial server and the “other” server is managed.
As I write some information in the code you will not be able to use the code “as is” but have to delete these lines.
First I just get the Login Guid. You’ll now ask: “How the hell did he get the login guid…? This file is supposed to be on the “other” server where no session variables are available…!” Right, I tested the RqlBridge on just ONE server (my editorial server), but the functionality also works when there are two servers.
sLoginGUID = Session("LoginGUID") 'Then the RQL statement is written in the variable "xmlString". xmlString = "<IODATA loginguid=""" & sLoginGUID & """>"&_ "<ADMINISTRATION>"&_ "<PROJECTS action=""list""/>"&_ "</ADMINISTRATION>"&_ "</IODATA>" 'Here we call the file "RqlBridge.asp" (on our editorial server) 'and transfer the RQL statement (xmlString) as the content of 'the parameter sXmlData. 'As written above the RqlBridge is just being used to execute the RQL. 'So as a result of this call we receive the server response from the editorial server. RqlRequest = GetServerAnswer("http://localhost/cms/plugins/remoterql/rqlbridge.asp?sXmlData=" & xmlString) Response.Write "<br>Server Response:" & server.htmlencode(RqlRequest) & "<p>" 'The function GetServerAnswer just calls an URL and returns the response. 'This is not related to the Management Server but is more a general functionality. Function GetServerAnswer(sUrl) Dim objHTTP, sServerAnswer Set objHTTP = Server.CreateObject("WinHttp.WinHttpRequest.5.1") objHTTP.SetTimeouts 0, 3000, 2000, 5000 objHTTP.open "GET", sUrl, false objHTTP.send if err.Number <> 0 then sServerAnswer=err.Number err.Clear end if on error goto 0 GetServerAnswer = sServerAnswer end function
Ready! We are now able to create calls on server A that will be executed on server B. I don’t know if this is helpful for much people but at least I wanted to point out this option.
As soon as you would like to read out the creation date of a page or the appearance schedule for a page you’ll notice that the dates are not really readable as they are just floating point number. So if you would like to display a date in a way that people can read it, you have to encode the date. If you would like to save a date….you have to decode it previously ;) The code below demonstrates both directions. If you create a plugin based on this code you will see how a serial date will be converted into a floating point number and vice versa.
<% 'converts a serial date into a floating point number that can be stored into the database mydate = "11/11/2010" set RQLObject = Server.CreateObject("RDCMSAsp.RdPageData") mydate = RqlObject.EncodeDate(myDate) response.write mydate & "<br>" mydate = "30493" set RQLObject = Server.CreateObject("RDCMSAsp.RdPageData") mydate = RqlObject.DecodeDate(myDate) response.write mydate & "<br>"'converts a date (floating point number) into a serial date ....that can be understood by humans ;-) %>
In order to enhance the overview of the code in your applications you might want to have an area where you just place the RQL functions and another area where you implement the logic. But even the execution of the RQL statements can be excluded in a seperate function. Of course this is not that much but at least we save a few lines of code.
function sendXML (XMLString) set objData = server.CreateObject("RDCMSASP.RdPageData") objData.XmlServerClassName = "RDCMSServer.XmlServer" sendXML = objData.ServerExecuteXml(XMLString, sErrors) if sErrors <> "" then response.write "Errors occured: " & sErrors & chr(13) & XMLString & "<br>" end if objData = NULL end function
If you found this article helpful and would like to see, what other users have done with RQL, then please visit the Community web site under www.SolutionsExchange.info
If you find any errors or have questions, please just leave a comment and I’ll try to help. If you’re interested in more RQL related articles then….right…leave a comment.
Have fun with RQL!
Source: RQL in a nutshell - Part II
© copyright 2011 by Manuel Schnitger