Enterprise Integration Zone is brought to you in partnership with:

Pascal is a senior JEE Developer and Architect at 4Synergy in The Netherlands. Pascal has been designing and building J2EE applications since 2001. He is particularly interested in Open Source toolstack (Mule, Spring Framework, JBoss) and technologies like Web Services, SOA and Cloud technologies. Specialties: JEE XML Web Services Mule ESB Maven Cloud Technology Pascal is a DZone MVB and is not an employee of DZone and has posted 55 posts at DZone. You can read more from them at their website. View Full User Profile

Use Mule to Sync WordPress Sites

03.04.2013
| 2336 views |
  • submit to reddit
I recently thought about to create a process with which I could keep two instances of WordPress in sync. I wanted to see if I could do this with Mule. I came up with the following solution:

  • Receive the RSS feed of a new post in Mule flow
  • Use the content of the RSS feed to post to the other wordpress instance by using XML-RPC
  • Have it running on CloudHub so I don’t have to setup my own Muleserver


So lets start a new CloudHub project. Since I am a big fan of Netbeans I use the Maven based approach (I must admit I have tried to use MuleStudio for this but it didn’t bring me the productivityboost I hoped for).
I created the Mule project with:

<?xml version="1.0" encoding="UTF-8"?>
<mule xmlns="http://www.mulesoft.org/schema/mule/core"
      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
      xmlns:http="http://www.mulesoft.org/schema/mule/http"
      xmlns:rss="http://www.mulesoft.org/schema/mule/rss"
      xmlns:spring="http://www.springframework.org/schema/beans"
    xsi:schemaLocation="
        http://www.mulesoft.org/schema/mule/core http://www.mulesoft.org/schema/mule/core/3.1/mule.xsd
        http://www.mulesoft.org/schema/mule/http http://www.mulesoft.org/schema/mule/http/3.1/mule-http.xsd
        http://www.mulesoft.org/schema/mule/rss http://www.mulesoft.org/schema/mule/rss/3.1/mule-rss.xsd
        http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">
    <spring:bean name="xmlRpcHelper" class="net.pascalalma.rss.XmlRpcHelper">
        <spring:constructor-arg value="http://www.pragmatic-integrators.com/xmlrpc.php" type="java.lang.String"/>
        <spring:constructor-arg value="UserName" type="java.lang.String"/>
        <spring:constructor-arg value="Password" type="java.lang.String"/>
    </spring:bean>
    <spring:bean name="entryReceiver" class="net.pascalalma.rss.EntryReceiver">
        <spring:constructor-arg ref="xmlRpcHelper"/>
    </spring:bean>
    <flow name="poll-and-post">
        <poll frequency="36000000">
            <http:outbound-endpoint address="http://www.redstream.nl/feed/" />
        </poll>
        <rss:feed-splitter />
        <component>
            <spring-object bean="entryReceiver"/>
        </component>
    </flow>
</mule>

As you can see I poll the website ‘www.redstream.nl’ once each 10 hours. The RSS feed I receive is split and sent to my custom made component ‘entryReceiver’. It would be nice to use a XML-RPC endpoint here but this isn’t created yet (and actually I don’t feel like it neither). The EntryReceiver looks like:

package net.pascalalma.rss;

import org.mule.api.annotations.param.Payload;
import com.sun.syndication.feed.synd.SyndEntry;

public class EntryReceiver {

    XmlRpcHelper xmlRpcHelper = null;

    public EntryReceiver(XmlRpcHelper helper) {
        xmlRpcHelper = helper;
    }
    public void readEntry(@Payload SyndEntry entry) throws Exception {

        // Get the title
        String title = entry.getTitle();

        // Check if title exist in current blogs on the new blogsite
       if (!xmlRpcHelper.titleExists(title)) {
            xmlRpcHelper.post(entry);

        } else {
            // Skip this post
        }
    }
}

Disclaimer: just wanted to see if it worked, I did not try to build a robust solution that had to work for every WordPress site, so you are warned!

And the bean where the dirty work is done:

package net.pascalalma.rss;

import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.xmlrpc.XmlRpcException;
import org.apache.xmlrpc.client.XmlRpcClient;
import org.apache.xmlrpc.client.XmlRpcClientConfigImpl;

import com.sun.syndication.feed.synd.SyndContentImpl;
import com.sun.syndication.feed.synd.SyndEntry;

public class XmlRpcHelper {

    private String url;
    private String userName;
    private String password;
    XmlRpcClient client = new XmlRpcClient();

    public XmlRpcHelper(String url, String u, String p) {
        this.url = url;
        this.userName = u;
        this.password = p;

        XmlRpcClientConfigImpl config = new XmlRpcClientConfigImpl();
        try {
            config.setServerURL(new URL(url));
        } catch (MalformedURLException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        client.setConfig(config);
    }

    public boolean titleExists(String title) {
        return getRecentTitles().contains(title);
    }

    public void post(SyndEntry entry) {
        StringBuilder content = new StringBuilder("<content><title>").append(entry.getTitle()).append("</title>");
        List<SyndContentImpl> contents = entry.getContents();

        for (SyndContentImpl syndContent : contents) {
            content.append(syndContent.getValue());
        }
        content.append("</content>");
        try {
            client.execute("blogger.newPost", new Object[]{"bla", 1,
                        userName, password, content.toString(), true});
        } catch (XmlRpcException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }

    private List<String> getRecentTitles() {
        List<String> titles = new ArrayList<String>();
        try {
            Object token = client.execute("blogger.getRecentPosts", new Object[]{"bla", 1,
                        userName, password, 10});

            Object[] result = (Object[]) token;
            for (int i = 0; i < result.length; i++) {
                titles.add(getTitle((HashMap<String, Object>) result[i]));
            }
        } catch (XmlRpcException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
            // return null;
        }
        return titles;
    }

    private static String getTitle(Map response) {
        String title = null;
        String content = (String) response.get("content");

        if (content != null) {
            title = content.substring(content.indexOf("<title>") + 7,
                    content.indexOf("</title>"));
        }
        return title;
    }
}

One thing that kept me busy for a while was that the first String in the Object array that is supplied with the XmlRpc call may contain anything as long as it contains something. An empty String “” is ignored in the call and will lead to an invalid Username/Password message.

If all this is in place you can build the project with: ‘mvn clean install’. This will create a zip file in the target directory. This zip file can then be uploaded with your dashboard to your CloudHub instance and that’s it! As you can see the two sites ‘www.redstream.nl’ and ‘www.pragmatic-integrators.com’ are know kept in sync (with a max. gap of 10 hrs). Of course the copied post is not an exact clone of the original (I am loosing info about the Author, Categories, etc. and images are referred to at the original location) but it shows that the main idea works!

Published at DZone with permission of Pascal Alma, author and DZone MVB. (source)

(Note: Opinions expressed in this article and its replies are the opinions of their respective authors and not those of DZone, Inc.)