cancel
Showing results for 
Search instead for 
Did you mean: 
cancel
4542
Views
8
Helpful
12
Replies

Write to XML file on HTTP Server with UCCX 8.x

Samuel Womack
Level 5
Level 5

This is for UCCX 8.5.1

THIS IS NOT AN HTTP TRIGGER

I need to be able to WRITE to an XML file via HTTP (straight up HTTP at this point e.g. http://<ip address>/*.xml); I know my web server is working as I can Load the Data of the XML file into a Create XML Document step (from the Create URL Doc Step (getting the file)).

Let's assume my XML file is the below (keeping it simple); How exactly would I go about changing the text field of the OVERRIDE element to say Open...again I cannot use the DOC repository.

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

<!-- This file is written to by an automated process; do not -->

<!-- edit by hand as your changes will be lost.              -->

<SERVICE_OVERRIDE>

<OVERRIDE>Closed</OVERRIDE>

</SERVICE_OVERRIDE>

12 Replies 12

Anthony Holloway
Cisco Employee
Cisco Employee

This is very easy to do, and it is mostly done on the web server, but there is a small chunk to do within UCCX.

I can give you a small PHP sample along with the UCCX example to help draw the picture.

PHP


     

     

     

        $override

     

    EOT;

    $file = 'servicestatus.xml';

    file_put_contents($file, $xml);

    echo "true";

  } else {

    echo "false";

  }

?>

UCCX

Variables

String http_base_url = "http://someserver/updater/"

String http_request_url = ""

String http_response = ""

String override = ""

Script

Start

Set override = "Closed"

Set http_request_url = http_base_url + "?override=" + override

Set http_response = URL[http_request_url]

If (http_response == "true")

  True

    /* The update worked */

  False

    /* The update failed */

End

What happens is this:

  1. The UCCX script sends an HTTP GET request to your PHP script on the web server at: http://someserver/updater/?override=Closed
  2. The PHP script checks to the existance of the override GET parameter, and stores it in the variable $override
  3. The PHP script generates the complete XML to be written to the file, including the value in $override
  4. The PHP script writes the new XML to the file
  5. The PHP script exits while writing "true" the standard output, which the UCCX script receives as the returned value.
  6. UCCX just checks to see if it got back the "true" and now it knows the update worked.

I hope that all makes sense, and that you can see now that you'll have to work on the web server/with the server admin to get a working solution put together.

Anthony Holloway

Please use the star ratings to help drive great content to the top of searches.

Do you (or anyone else) know of a way to keep most of the work on the UCCX server such as using a Java Class such as the JDOM?

That's actually a very interesting questiob/approach to solving this.  I unfortunately cannot help here, because I do not have any experience with JDOM.  Perhaps we'll wait and see together if someone responds.  Good luck!

Anthony Holloway

Please use the star ratings to help drive great content to the top of searches.

Anthony,

To use JDOM do this:

  1. Get a version of jdom from the web.  I have used jdom-1.1.3.jar with UCCX successfully
  2. Install it into the document repository in the classpath directory
  3. Under System | Custom classes configuration move the library into the righthand window and press update
  4. Go to CCX Serviceability and restart the CCX Engine and CCX Adminstration; do this bit on both servers if you have HA

Now that you have the java library installed you can run the CCX Editor and leverage it:

  • In the variable pane, create:
    1. org.jdom.Document called jdomServiceFile
    2. org.jdom.Element called jdomRootElement
    3. org.jdom.Element called jdomElementOverride
    4. Document called docServiceFile
    5. Document called docNewServiceFile
  • Now you need to leverage in-line java code:

Set jdomServiceFile = {

          org.jdom.input.SAXBuilder myBuilder;

          myBuilder = new org.jdom.input.SAXBuilder();

          return myBuilder.build(docServiceFile.getInputStream() );

          }

Do:      {

          jdomServiceFile.getRootElement().getChild("OVERRIDE").setText("Closed");

          }

Set docNewServiceFile = {

          org.jdom.output.XMLOutputter OutputObject;

          OutputObject = new org.jdom.output.XMLOutputter();

          return OutputObject.outputString(jdomServiceFile );

          }

The idea here is you first export the Cisco  document into a JDOM document using the standard Java InputStrem  system.  Then you modify the node.  Finally you output the document as a  string back into the Cisco Document.  Not the cleanest way but given  the limited amount of object access we have it does work. 

I wouldn't recommend this for large XML documents as  string manipulation like this can be memory intensive but for small  stuff like this it will work just fine.

-Steven

Edit to add:  If you are using UCCX 9.X you'll need to use the jdom2 library.  Just replace all org.jdom objects with org.jdom2 objects and this same code will work.

Please help us make the communities better.  Rate helpful posts!

Message was edited by: Steven Griffin

Please help us make the communities better. Rate helpful posts!

Wow, that was pretty detailed.  Thank you for taking the time to write that up.

Anthony Holloway

Please use the star ratings to help drive great content to the top of searches.

Update to my post:

    I recently discovered that UCCX 9.0(2) and onward using the jdom2 library has a few issues which I have recently run into with a customer today.  I am adding to this post with the results of my experience so that others might benefit.  My comments here assume some knowledge of Computer Science / Java and how methods (function calls) work behind the scenes.

    First, know that jdom2 has decided to incorporate templates (aka generics) as arguments to certain methods. This shouldn't be an issue if you don't call those methods. The issue does occur when both static and template arguments exist for the same method. I.E. the method is overridden.

The UCCX engine, as far as I can tell, has some issues discerning the datatype when the input argument isn't statically known for all instances of that method.  When this occurs an exception (ambiguous method) is thrown at compile time or you'll get a Marshalling exception at runtime.

    In the example above I am simply accessing an existing node and then setting its value.  However, what happens if the node OVERRIDE doesn't exist? In that case we need to create it. The method do to this is called addContent.  In jdom1.1 it works fine but jdom2 it has arguments that can be generics.  So what seems simple just doesn't work.

Let's edit the DO statement above to check for a non existent element and add it if missing:

    Do:      {

      jdomElement = jdomServiceFile.getRootElement().getChild("OVERRIDE");

      if (jdomElement == null) {

        jdomElement = new org.jdom2.Element("OVERRIDE");

        jdomRootElement.addContent(jdomElement);

        }

      jdomElement.setText("Closed");

    }

This code is valid on UCCX 8.X and lower when jdom1.1 is used.  However in jdom2 'addContent' can accept templates (generics) as arguments. The UCCX engine cannot discern the datatype and throws an exception.  To get around this issue you need to find a set of methods that don't offer generic types as arguments.  Fortunately, JDOM2 has implemented the 'factory' methodology to assist you with creating the correct datatypes. 

Lets edit the "DO' section to read.

    Do:      {

      org.jdom2.DefaultJDOMFactory jdomFactory = new org.jdom2.DefaultJDOMFactory();

      jdomElement = jdomServiceFile.getRootElement().getChild("OVERRIDE");

      if (jdomElement == null) {

        jdomElement = new org.jdom2.Element("OVERRIDE");

        jdomFactory.addContent(jdomRootElement, jdomElement);

          }

      jdomElement.setText("Closed");

          }

In this case the addContent method of the DefaultJDOMFactory object isn't overriden to accept templates (generics) as arguments so the UCCX Engine can add our new node to the XML tree.


Please help us make the communities better.  Rate helpful posts!

Please help us make the communities better. Rate helpful posts!

I wouldn't even use JDOM in that case: I would use the built-in Classes for this..if you absolutely have to write raw code like this in order to acheive the result you are trying to accomplish..otherwise..Standard CCX Step can do the same thing with less verbiage and ultimately less confusion when someone else reads the stuff we write..I'm Attaching the Document (XML) you will want to use for this Code..It works as Advertised if you throw it in a Do Step...

{

     //OVERRIDE State Document Location

     Document dCDoc = DOC[State.xml];

     javax.xml.parsers.DocumentBuilderFactory stateFactory =

          javax.xml.parsers.DocumentBuilderFactory.newInstance();

     javax.xml.parsers.DocumentBuilder stateBuilder =

          stateFactory.newDocumentBuilder();

     //Load Data into Memory using DOM

     org.w3c.dom.Document doc = stateBuilder.parse(dCDoc);

     //Find the Root Node

     org.w3c.dom.Node ovrRide = doc.getFirstChild();

     //Go to the Node

     org.w3c.dom.Node state = doc.getElementsByTagName("STATE").item(0);

     //Set the Value of the Node

     //To what's stored in the NewSysState String

     state.setTextContent(sNewSysState);

      /*

     TEST

      org.w3c.dom.Element elem = (org.w3c.dom.Element)state;

      sSysState = elem.getFirstChild().getNodeValue();

     */

     //This is creating a new XML Document 

     //Ref: http://docs.oracle.com/javase/tutorial/jaxp/xslt/writingDom.html

     javax.xml.transform.TransformerFactory transFact =

          javax.xml.transform.TransformerFactory.newInstance();

     javax.xml.transform.Transformer transformer = transFact.newTransformer();

     javax.xml.transform.dom.DOMSource source =

         new javax.xml.transform.dom.DOMSource(doc);

     javax.xml.transform.stream.StreamResult result =

     new javax.xml.transform.stream.StreamResult(new java.io.StringWriter());

     transformer.transform(source,result);

     //Set Value of this STRING as the XML Document

     sDocName = result.getWriter().toString();

     //Create "Cisco" (class) Document from STRING

     d=TEXT[sDocName];

}

Therein lies the rub, doesn't it?  Use the built-in classes or use a custom class. 

If you take the original code I wrote above  with the new 'DO' code it comes out to twelve lines. You accomplish the  same in fourteen. Both acomplish the same task in approximately the same amount of code.

Which is easier to read?  Which will be easier to  maintain?  There are trade-offs to each.   Personally, I will trade a bit of maintenance headache for readability. 

Please help us make the communities better.  Rate helpful posts!

Please help us make the communities better. Rate helpful posts!

Steven,

 

I know this is a very old post but I tried that but get a java.lang.NullPointerException error.  See attachment. 

 

Seems like the point of the code snippet is to initialize the root node.  Would this make sense:

jdomElement = new org.jdom.Element("ANNOUNCEMENT");
jdomRootElement = new org.jdom2.Element("ANNOUNCEMENT");

 

FYI I am not a java developer but I'm doing a migration to UCCX 11.6 for a customer and I see that you wrote the script.  I'm trying to port from jdom 1.x to 2.x since UCCX 11.6 supports java 7 but jdom 1.x does not.

Hi,

Drilling down to the basics, you need a web server and a client which will update an XML file that is being served, the client being UCCX.

To update the XML file that is being served, you can either use server-side PHP as suggested, or use Java in a manner similar to SOAP (again, see Anthony's article) to just HTTP POST the entire file with the modified value.

If you are planning to use this XML file to determine your Call Center status, you have only 2 possible instances of the file: open and closed. Hence, instead of updating the file, why not overwrite it?

The above PHP code also does something similar, it does not manipulate XML DOM or any such thing; you don't need to go for such a complicated solution unless simple file-overwrite does not do what you need. In case you do need DOM, upload the JDOM classes on the UCCX and use them.

Thanks & Regards, Anirudh "Protocol, then product"

Anthony, Does your HTTP script need a specific License?

Thank you

No, it should work in Standard, Enhanced, or Premium.

http://www.cisco.com/en/US/customer/prod/collateral/voicesw/custcosw/ps5693/ps1846/data_sheet_c78-629807.html#wp9000455

Anthony Holloway

Please use the star ratings to help drive great content to the top of searches.

Getting Started

Find answers to your questions by entering keywords or phrases in the Search bar above. New here? Use these resources to familiarize yourself with the community: