Talking XMLRPC to a Wordpress instance

This is a short example demonstration how to use the Apache XMLRPC library to talk to a running Wordpress instance.

Wordpress 1.5 supports various XMLRPC operations by default ( MT & Blogger APIs for example ) however the two shown below are "demo" operations that all Wordpress installations should support and require no authentication.

To run this example you will need to include the dependencies - Apache XMLRPC & Jakarta COMMONS Codec - however if you are lazy, here is my "xmlrpc-2.0-dep.jar" JAR containing both.

Code

JAVA:
  1. import java.util.Vector;
  2.  
  3. import org.apache.xmlrpc.XmlRpcClient;
  4.  
  5. public class XMLRPCTest {
  6.  
  7.    /**
  8.     * @param args
  9.     */
  10.    public static void main(String[] args) {
  11.  
  12.       try {
  13.          
  14.          Object result;
  15.  
  16.          /* You can specify an alternative target URL here */
  17.          XmlRpcClient xmlrpc = new XmlRpcClient ("http://blog.lobstertechnology.com/xmlrpc");
  18.          
  19.          
  20.          /*
  21.           * demo.sayHello operation, returns a java.lang.String
  22.           *
  23.           */
  24.          result = xmlrpc.execute( "demo.sayHello", new Vector() );
  25.          System.out.println( "demo.sayHello: " + result +
  26.             " (" + result.getClass().getName() + ")" );
  27.  
  28.          
  29.          /*
  30.           * demo.addTwoNumbers operation, returns a java.lang.Integer
  31.           *
  32.           */
  33.          Vector params = new Vector ();
  34.          params.addElement ("5");
  35.          params.addElement ("8");
  36.          result = xmlrpc.execute( "demo.addTwoNumbers", params );
  37.          System.out.println( "demo.addTwoNumbers: " + result +
  38.             " (" + result.getClass().getName() + ")" );
  39.          
  40.       } catch ( Exception e ) {
  41.          e.printStackTrace();
  42.       }
  43.      
  44.    }
  45.  
  46. }

Example

CODE:
  1. demo.sayHello: Hello! (java.lang.String)
  2. demo.addTwoNumbers: 13 (java.lang.Integer)

Related Links

XMLRPCTest.java - Java Source Code
xmlrpc-2.0-dep.jar - Dependencies
Apache XMLRPC - http://ws.apache.org/xmlrpc/
Jakarta COMMONS Codec - http://jakarta.apache.org/commons/codec/

[Oracle Toplink] Importing a 10.1.3DP3 project into the 10.1.3DP4 workbench doesnt work…

Velocimacro – Generate a HTML Select box and its Options

A quick and simple Velocimacro to generate HTML Select boxes and its Options; automatically selects the correct option based on the value given.

You can place this #macro anywhere in your Velocity templates but I used my global VM_global_library.vm file.

Code

CODE:
  1. #macro( generateSelectBox $name $options $value )
  2. <select name='$name' value='$value'>
  3. #foreach ( $option in $options )
  4.   #set( $selected = "" )
  5.   #if ( $option == $value )
  6.     #set( $selected = "selected='true'" )
  7.   #end
  8.   <option value='$option' $selected>$option</option>
  9. #end
  10. </select>
  11. #end

Example Usage

CODE:
  1. #generateSelectBox( "enabled" ["Y","N"] $form.enabled )

The resulting HTML:

CODE:
  1. <select name='enabled' value='N'>
  2.   <option value='Y'>Y</option>
  3.   <option value='N' selected='true'>N</option>
  4. </select>

Addendum

11th November 2005 : Thanks to MATT for pointing out the FreeMarker template engine as a promising replacement for Velocity. ;)

Java Document to String

This is a very simple utility function to produce an indented XML document as a String given a Document. It throws a TransformerException if anything drastic goes wrong.

JAVA:
  1. import java.io.*;
  2. import org.w3c.dom.Document;
  3. import javax.xml.transform.*;
  4. import javax.xml.transform.dom.DOMSource;
  5.  
  6. ...
  7.  
  8. public static String documentToString( Document document ) throws TransformerException {
  9.     TransformerFactory tFactory = TransformerFactory.newInstance();
  10.     Transformer transformer = tFactory.newTransformer();
  11.    
  12.     DOMSource source = new DOMSource(document);
  13.     StringWriter sw = new StringWriter();
  14.     StreamResult result = new StreamResult(sw);
  15.    
  16.     transformer.setOutputProperty( OutputKeys.INDENT, "yes" );
  17.     transformer.transform(source, result);
  18.    
  19.     return sw.toString();
  20. }

Velocity if statement is type sensitive…

Problem

I discovered that comparisons in Velocity if statements are type-sensitive the hard way.

For example, I am trying to display the 'selected' option in a html <SELECT> object. The list of possible values is $list, each is a simple 'NameValuePair' value object { String name, String value }.

The object I am editing in this form is $obj, and the field I am testing against is $obj.typeId defined as a long.

CODE:
  1. <select name='typeId' value='$!{obj.typeId}'>
  2. #foreach ( $item in $list )
  3.   #if ( $item.value == $obj.typeId )
  4.     <option value='$item.value' selected='true'>$item.name</option>
  5.   #else
  6.     <option value='$item.value'>$item.name</option>
  7.   #end
  8. #end
  9. </select>

However, the if statement on line 3 is actually comparing a String to a long which are of course never going to be equal.

Solution

The easiest work around in this case was to convert the $obj.typeId into a String before the comparison.

CODE:
  1. <select name='typeId' value='$!{obj.typeId}'>
  2. #set ( $typeId = "$!{obj.typeId}" )
  3. #foreach ( $item in $list )
  4.   #if ( $item.value == $typeId )
  5.     <option value='$item.value' selected='true'>$item.name</option>
  6.   #else
  7.     <option value='$item.value'>$item.name</option>
  8.   #end
  9. #end
  10. </select>

Any comments / feedback welcomed ;)

Velocity Templates and Newlines

If you're reading this article you've probably encounted the same problem as I have. I was trying to put a newline '\n' character in the value of a variable in a Velocity template.

Attempt 1:

I assumed \n would work...

CODE:
  1. #if ( !$foo )
  2.   #set ( $foo = "There was no foo set in the Context.\nPlease do something about it." )
  3. #end

This produced There was no foo set in the Context.\nPlease do something about it. as the value of $foo.

Attempt 2:

I just thought this was worth a shot :D

CODE:
  1. #if ( !$foo )
  2.   #set ( $foo = "There was no foo set in the Context.
  3. Please do something about it." )
  4. #end

And the template failed to compile

Solution:

Basically, the easiest way I found is to place the newline, carriage return or other special character in the context.

JAVA:
  1. public Template handleRequest( HttpServletRequest request, HttpServletResponse response, Context context )
  2. {
  3.     ...
  4.  
  5.     context.put( "nl", "\n" );
  6.     context.put( "cr", "\r" );
  7.  
  8.     ...
  9. }

And in your template:

CODE:
  1. #if ( !$foo )
  2.   #set ( $foo = "There was no foo set in the Context.${nl}Please do something about it." )
  3. #end

Maybe not the best solution but it works for me. If you expect to use it across your entire application I suggest you override VelocityServlet.createContext in your Servlet to add these characters to every context in your application.

Example:

JAVA:
  1. protected Context createContext( HttpServletRequest request, HttpServletResponse response ) {
  2.     Context context = super.createContext( request, response );
  3.    
  4.     context.put( "nl", "\n" );
  5.     context.put( "cr", "\r" );
  6.    
  7.     return context;
  8. }

Java Object Digester

I was working on a web-based application recently and wanted a lazy way to get data from a simple 'value object' out to the front end without having any hard-coded field names; I came up with this.

Basically, this method will take any Object, iterate through its methods looking for any of the format "get<something>" then place the returned value in a new child element of the document. Obviously the method getClass() will match this criteria and it is handled specially; its added as a comment, not an element.

JAVA:
  1. /**
  2. * <p>Converts a 'value object' into a Document.</p>
  3. *
  4. * <p>This method is expecting a simple value object, it will iterate through a list of
  5. * the objects methods looking for "get*" methods. The remainder of the method name
  6. * is considered the 'field name' ie. getName() - "Name".</p>
  7. *
  8. * <p>The generated document will contain a root element based on the name of the given
  9. * object. Each of its non-null fields will then follow as child elements.</p>
  10. *
  11. * <p>For example, class com.company.value.User which contains methods getName, getEmail and
  12. * getPhoneNumber.</p>
  13. *
  14. * <xmp>
  15. * <user>
  16. *   <name>Michael</name>
  17. *   <email>name@address.com</email>
  18. *   <phonenumber>555-3454</phonenumber>
  19. * </user>
  20. * </xmp>
  21. *
  22. * @author Michael Cutler (m@cotdp.com)
  23. * @param obj the value object to digest into a Document
  24. * @return A document containing the values of all the fields in the object
  25. * @throws ParserConfigurationException thrown if the XML documentbuilder fails
  26. */
  27. public static Document digestObject( Object obj ) throws ParserConfigurationException {
  28.     DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
  29.     DocumentBuilder documentBuilder = documentBuilderFactory.newDocumentBuilder();
  30.    
  31.     Document document = documentBuilder.newDocument();
  32.     Node rootElement  = document.createElement( getClassName(obj) );
  33.    
  34.     document.appendChild( rootElement );
  35.    
  36.     Method methods[] = obj.getClass().getMethods();
  37.     for ( int i = 0; i &lt;methods.length; i++ ) {
  38.         Method method = methods[i];
  39.         if ( method.getName().startsWith("get") ) {
  40.             String fieldName = method.getName().substring(3);
  41.             try {
  42.                 Object result = method.invoke( obj, null );
  43.                 if ( result != null ) {
  44.                     if ( fieldName.equals("Class") ) {
  45.                         Node child = document.createComment( result.toString() + " " );
  46.                         rootElement.appendChild( child );
  47.                     } else {
  48.                         Node child = document.createElement( fieldName );
  49.                         Node text = document.createTextNode( result.toString() );
  50.                         child.appendChild( text );
  51.                         rootElement.appendChild( child );
  52.                     }
  53.                 }
  54.             } catch ( Exception e ) { }
  55.         }
  56.     }
  57.    
  58.     return document;
  59. }
  60.  
  61.  
  62.  
  63.  
  64. /**
  65. * This method is package/no-package safe, lastIndexOf('.') will return -1 if
  66. * not found, since we add 1 to skip the '.' character anyway there is no problem
  67. * if '.' isn't found.
  68. *
  69. * @return a string representing the name of the class (without package name)
  70. */
  71. private static String getClassName( Object obj ) {
  72.     String name = obj.getClass().getName();
  73.     return name.substring( name.lastIndexOf('.') + 1 );
  74. }

For example, if your application stores information about a user - their name, email address & phone number - it may use a simple User value object shown below to represent that information.

JAVA:
  1. package com.company.value;
  2.  
  3. /**
  4. * @author Michael Cutler (m@cotdp.com)
  5. * @version 1.0
  6. */
  7. public class User {
  8.  
  9.     private String name;
  10.     private String email;
  11.     private String phoneNumber;
  12.  
  13.     public String getEmail() {
  14.         return email;
  15.     }
  16.    
  17.     public void setEmail(String email) {
  18.         this.email = email;
  19.     }
  20.    
  21.     public String getName() {
  22.         return name;
  23.     }
  24.    
  25.     public void setName(String name) {
  26.         this.name = name;
  27.     }
  28.    
  29.     public String getPhoneNumber() {
  30.         return phoneNumber;
  31.     }
  32.    
  33.     public void setPhoneNumber(String phoneNumber) {
  34.         this.phoneNumber = phoneNumber;
  35.     }
  36.    
  37. }

Fed into my digestObject() method the resulting Document would look something like:

XML:
  1. <user>
  2.    <name>Michael Cutler</name>
  3.    <email>name@address.com</email>
  4.    <phonenumber>555-3454</phonenumber>
  5. </user>

With your data now in XML you can easily apply XSL transforms on it to render a HTML view or form, use XPath or Schema validation against it to validate the structure of the document and its data or, output it to another system like Velocity for example...

Any comments / questions please post them here, Thanks...

Java Snippet – ANT Jar Task

Builds a JAR file Test.jar and generates a manifest specifying that class Test is the Main-Class.

XML:
  1. <target name="dist" depends="dist-clean">
  2.     <jar jarfile="Test.jar" index="true" compress="true">
  3.         <fileset dir="classes"/>
  4.         <fileset dir=".">
  5.             <include name="Test.properties"/>
  6.         </fileset>
  7.         <manifest>
  8.             <attribute name="Built-By" value="Michael Cutler"/>
  9.         <attribute name="Main-Class" value="Test"/>
  10.         </manifest>
  11.     </jar>
  12. </target>

Java Snippet – Using SecureRandom

A better random number generator

JAVA:
  1. import java.security.SecureRandom;
  2.  
  3. ...
  4.  
  5. public static SecureRandom random = null;
  6.  
  7. static {
  8.     try {
  9.         random = SecureRandom.getInstance("SHA1PRNG");
  10.         random.setSeed( random.generateSeed(256) );
  11.     } catch( Exception e ) {
  12.         e.printStackTrace();
  13.     }
  14. }

Java Snippet – Fast File Copy

When using JDK 1.4 and above...

JAVA:
  1. public static void copyFile(File in, File out) {
  2.     try {
  3.         FileChannel sourceChannel = new FileInputStream(in).getChannel();
  4.         FileChannel destinationChannel = new FileOutputStream(out).getChannel();
  5.         sourceChannel.transferTo(0, sourceChannel.size(), destinationChannel);
  6.         // or, you can also copy it this way
  7.         // destinationChannel.transferFrom(sourceChannel, 0, sourceChannel.size());
  8.         sourceChannel.close();
  9.         destinationChannel.close();
  10.     } catch ( Exception e ) {
  11.         e.printStackTrace();
  12.     }
  13. }