Contact Us 1-800-596-4880

Atom Module Reference

The name Atom applies to a pair of related standards. The Atom Syndication Format is an XML language used for web feeds, while the Atom Publishing Protocol (AtomPup or APP) is a simple HTTP-based protocol for creating and updating web resources. Mule contains support for both.

Namespace and Syntax

XML namespace:

http://www.mulesoft.org/schema/mule/atom

XML Schema location:

http://www.mulesoft.org/schema/mule/atom http://www.mulesoft.org/schema/mule/atom/3.4/mule-atom.xsd

Features

The Mule Atom Module includes an implementation of Apache Abdera, making it possible to integrate easily with Atom feeds and Atom Publishing Protocol servers from within a Mule configuration.

The module supports the following capabilities:

  • Consuming Atom feeds

  • Publishing Atom entries

  • Server side AtomPub support as a Mule application

ETags

The Atom HTTP endpoint respects ETags and the 304 Not Modified response code by default, so you don’t need to worry about consuming unnecessary updates.

Example Configurations

Consuming Feeds and Other Atom Resources

One of the most common patterns is for integrating with Atom is polling for feed updates. With Mule this can be done quite easily. You must first white your class which receives an Atom Entry:

EntryReceiver.java
package org.mule.module.atom.example;

import org.apache.abdera.model.Feed;

public class EntryReceiver {
    public void processEntry(Entry entry) throws Exception {
        //process the entry
    }
}

Use an atom feed splitter to split an incoming feed into individual messages so the component method will be invoked for each entry in the feed. The flow configuration would look like so:

<flow name="eventConsumer">
    <poll frequency="10000">
        <http:outbound-endpoint address="http://localhost:9002/events"/>
    </poll>
    <atom:feed-splitter/>
    <atom:entry-last-updated-filter/>
    <component class="org.mule.module.atom.event.EntryReceiver"/>
</flow>

The atom:entry-last-updated-filter is optional. It should only be used to filter older entries from the feed. Note that the atom:entry-last-updated-filter should come after the atom:feed-splitter/ since you need to split the feed into entries so that the filter can process them. Also note that we do not set a lastUpdate date on the filter. This implies the default behavior that all available entries will be read before the processing of any entries that are new as of the last read.

Accessing the Feed Itself

If you need access to the feed itself, parse it using the object-to-feed transformer:

<flow name="eventConsumer">
    <poll frequency="10000">
        <http:outbound-endpoint address="http://localhost:9002/events"/>
    </poll>
    <atom:object-to-feed-transformer/>
    <component class="org.mule.module.atom.event.FeedReceiver"/>
</flow>

Now your component will only be invoked once for each feed change no matter how many entries were added or updated. The method on your component should expect a org.apache.abdera.model.Feed object.

FeedReceiver.java
package org.mule.module.atom.example;

import org.apache.abdera.model.Feed;

public void processFeed(Feed feed) throws Exception {
    //do stuff
}

If you want access to the feed object while using the feed splitter, it is available via a header on the current message called \'feed.object'.

Accessing Feeds over Other Protocols

You can receive feeds and process them using other Mule connectors such as JMS, File, or XMPP. To do this, the atom feed needs to be served over the connector. For instance, an atom document is sent over JMS or polled from a file. The atom schema defines a atom:feed-splitter/ message processor that can split messages received from an endpoint, like so:

Consuming an Atom feed over JMS
<flow name="feedSplitterConsumer">
    <jms:inbound-endpoint queue="feed.in">
        <atom:feed-splitter/>
    </jms:inbound-endpoint>
    <component class="org.mule.module.atom.event.EntryReceiver"/>
</flow>
Consuming an Atom feed from a file
<flow name="feedSplitterConsumer">
    <file:inbound-endpoint  path="${mule.working.dir}" pollingFrequency="1000" >
        <file:filename-wildcard-filter pattern="*.atom"/>
        <atom:feed-splitter/>
    </file:inbound-endpoint>
    <component class="org.mule.module.atom.event.EntryReceiver"/>
</flow>

Implementing an AtomPub Server

Abdera’s server side component centers on the notion of a Provider. A Provider manages a service’s Workspaces and Collections.

You can create an AtomPub service in Mule by using atom:component/ XML element and reference an Abdera service context.

Creating the Abdera Service Context

The following example shows how to create an Abdera context that builds a JCR repository to store atom entries. These entries can then be served as a feed.

abdera-config.xml
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:a="http://abdera.apache.org"
       xsi:schemaLocation="
           http://abdera.apache.org http://abdera.apache.org/schemas/abdera-spring.xsd
           http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-current.xsd">

    <a:provider id="provider">
        <a:workspace title="JCR Workspace">
            <ref bean="jcrAdapter"/>
        </a:workspace>
    </a:provider>

    <bean id="jcrRepository" class="org.apache.jackrabbit.core.TransientRepository" destroy-method="shutdown"/>

    <bean id="jcrAdapter"
          class="org.apache.abdera.protocol.server.adapters.jcr.JcrCollectionAdapter" init-method="initialize">
        <property name="author" value="Mule"/>
        <property name="title" value="Event Queue"/>
        <property name="collectionNodePath" value="entries"/>
        <property name="repository" ref="jcrRepository"/>
        <property name="credentials">
            <bean class="javax.jcr.SimpleCredentials">
                <constructor-arg>
                    <value>username</value>
                </constructor-arg>
                <constructor-arg>
                    <value>password</value>
                </constructor-arg>
            </bean>
        </property>
        <property name="href" value="events"/>
    </bean>
</beans>

The <a:provider> creates an Abdera DefaultProvider and allows you to add workspaces and collections to it. This provider reference is used by the atom:component in Mule to store any events sent to the component.

<flow name="atomPubEventStore">
    <http:inbound-endpoint address="http://localhost:9002"/>
    <atom:component provider-ref="provider"/>
</flow>

Publishing to the Atom Component

You may also want to publish Atom entries or media entries to the atom:component/ or to an external AtomPub collection. Here is a simple outbound endpoint which creates an Abdera Entry via the entry-builder-transformer and POSTs it to the AtomPub collection:

<outbound-endpoint address="http://localhost:9002/events" mimeType="application/atom+xml;type=entry" connector-ref="HttpConnector">
    <atom:entry-builder-transformer>
        <atom:entry-property name="author" evaluator="string" expression="Ross Mason"/>
        <atom:entry-property name="content" evaluator="payload" expression=""/>
        <atom:entry-property name="title" evaluator="header" expression="title"/>
        <atom:entry-property name="updated" evaluator="function" expression="now"/>
        <atom:entry-property name="id" evaluator="function" expression="uuid"/>
    </atom:entry-builder-transformer>
</outbound-endpoint>

You could also create the Entry manually for more flexibility and send it as your Mule message payload. Here’s a simple example of how to create an Abdera Entry:

Create an Abdera Entry
package org.mule.providers.abdera.example;

import java.util.Date;

import org.apache.abdera.Abdera;
import org.apache.abdera.factory.Factory;
import org.apache.abdera.model.Entry;
import org.mule.transformer.AbstractTransformer;

public class EntryTransformer extend AbstractTransformer {
    public Object doTransform(Object src, String encoding) {
        Factory factory = Abdera.getInstance().getFactory();

        Entry entry = factory.newEntry();
        entry.setTitle("Some Event");
        entry.setContent("Foo bar");
        entry.setUpdated(new Date());
        entry.setId(factory.newUuidUri());
        entry.addAuthor("Dan Diephouse");

        return entry;
    }
}

You can also post Media entries quite simply. In this case it will take whatever your message payload is and post it to the collection as a media entry. You can supply your own Slug via configuration or by setting a property on the mule message.

Post Message Payload as Media Entry
<flow name="blobEventPublisher">
    <inbound-endpoint ref="quartz.in"/>
    <component class="org.mule.module.atom.event.BlobEventPublisher"/>

    <outbound-endpoint address="http://localhost:9002/events"
          exchange-pattern="request-response" mimeType="text/plain">
       <message-properties-transformer scope="outbound">
           <add-message-property key="Slug" value="Blob Event"/>
       </message-properties-transformer>
   </outbound-endpoint>
</flow>

Route Filtering

The atom module also includes an atom:route-filter. This allows ATOM requests to be filtered by request path and HTTP verb. The route attribute defines a type of URI Template loosely based on Ruby on Rails style Routes. For example:

"feed" or ":feed/:entry"

For reference, see the Ruby On Rails routing.

For example, this filter can be used for content-based routing in Mule:

Route Filtering
<flow name="customerService">
        <inbound-endpoint address="http://localhost:9002" exchange-pattern="request-response"/>
        <choice>
            <when>
                <atom:route-filter route="/bar/:foo"/>
                <outbound-endpoint address="vm://queue1" exchange-pattern="request-response"/>
            </when>
            <when>
                <atom:route-filter route="/baz" verbs="GET,POST"/>
                <outbound-endpoint address="vm://queue2" exchange-pattern="request-response"/>
            </when>
        </choice>
    </flow>

Configuration Reference

Component

Represents an Abdera component.

Table 1. Attributes of <component…​>
Name Type Required Default Description

provider-ref

string

no

The ID of the Atom provider that is defined as Spring bean.

No Child Elements of <component…​>

Feed Splitter

Splits the entries of a feed into single entry objects. Each entry is a separate message in Mule.

No Child Elements of <feed-splitter…​>

Filters

Entry Last Updated Filter

Will filter ATOM entry objects based on their last update date. This is useful for filtering older entries from the feed. This filter works only on Atom Entry objects not Feed objects.

Table 2. Attributes of <entry-last-updated-filter…​>
Name Type Required Default Description

lastUpdate

string

no

The date from which to filter events from. Any entries that were last updated before this date will not be accepted. The date format is: yyyy-MM-dd hh:mm:ss, for example 2016-12-25 13:00:00. If only the date is important you can omit the time part. You can set the value to \'now' to set the date and time that the server is started. Do not set this attribute if you want to receive all available entries then any new entries going forward. This is the default behavior and suitable for many scenarios.

acceptWithoutUpdateDate

boolean

no

true

Whether an entry should be accepted if it doesn’t have a Last Update date set.

No Child Elements of <entry-last-updated-filter…​>

Feed Last Updated Filter

Will filter the whole ATOM Feed based on its last update date. This is useful for processing a feed that has not been updated since a specific date.

This filter works only on Atom Feed objects.

Typically, it is better to set the lastUpdated attribute on an inbound ATOM endpoint with splitFeed=false rather than use this file, however, this filter can be used elsewhere in a flow.

Table 3. Attributes of <feed-last-updated-filter…​>
Name Type Required Default Description

lastUpdate

string

no

The date from which to filter events from. Any entries that were last updated before this date will not be accepted. The date format is: yyyy-MM-dd hh:mm:ss, for example 2008-12-25 13:00:00. If only the date is important you can omit the time part. You can set the value to \'now' to set the date and time that the server is started. Do not set this attribute if you want to receive all available entries then any new entries going forward. This is the default behavior and suitable for many scenarios.

acceptWithoutUpdateDate

boolean

no

true

Whether an entry should be accepted if it doesn’t have a Last Update date set.

No Child Elements of <feed-last-updated-filter…​>

Route Filter

Allows ATOM requests to be filtered by request path and HTTP verb.

Table 4. Attributes of <route-filter…​>
Name Type Required Default Description

route

string

no

The URI request path made for an ATOM request. This matches against the path of the request URL. The route attribute defines a type of URI Template loosely based on Ruby on Rails style Routes. For example: "feed" or "feed:/entry". For reference, see the Ruby On Rails routing

verbs

string

no

A comma-seperated list of HTTP verbs that will be accepted by this filter. By default all verbs are accepted.

No Child Elements of <route-filter…​>

Transformer

Entry Builder Transformer

A transformer that uses expressions to configure an Atom Entry. The user can specify one or more expressions that are used to configure properties on the bean.

No Attributes of <entry-builder-transfomer…​>

Table 5. Child Elements of <entry-builder-transformer…​>
Name Cardinality Description

entry-property

0..1

Object to Feed Transformer

Transforms the payload of the message to a org.apache.abdera.model.Feed instance.

No Child Elements of <object-to-feed-transformer…​>

Schema

Namespace: http://www.mulesoft.org/schema/mule/atom

Targeting Schemas (1):

Targeting Components:

Schema Summary

mule-atom.xsd

The Mule ATOM support makes it possible to integrate easily with Atom feeds and Atom Publishing Protocol servers via the Apache Abdera projec.

Target Namespace:

Defined Components:

Default Namespace-Qualified Form:

Local Elements: qualified; Local Attributes: unqualified

Schema Location:

Imports Schemas (4):

mule-schemadoc.xsd, mule.xsd, spring-beans-3.1.xsd, xml.xsd

Imported by Schema:

_mule-all-included.xsd

All Element Summary

component

Represents an Abdera component.

Content: complex, 2 attributes, attr. wildcard, 8 elements

Subst.Gr:may substitute for elements: mule:abstract-component, mule:abstract-message-processor

Defined: globally in mule-atom.xsd; see XML source

Used: never

entry-builder-transformer

A transformer that uses expressions to configure an Atom Entry.

Content: complex, 5 attributes, attr. wildcard, 2 elements

Subst.Gr: may substitute for elements: mule:abstract-transformer, mule:abstract-message-processor

Defined: globally in mule-atom.xsd; see XML source

Used: never

entry-last-updated-filter

Filters the whole ATOM Feed based on its last update date.

Type: feedLastUpdateFilterType

Content: complex, 3 attributes, attr. wildcard, 1 element

Subst.Gr: may substitute for elements: mule:abstract-filter, mule:abstract-message-processor

Defined: globally in mule-atom.xsd

Used: never

feed-splitter

Splits the entries of a feed into single entry objects.

Type: mule:baseSplitterType

Content: complex, 1 attribute, attr. wildcard, 2 elements

Subst.Gr: may substitute for elements: mule:abstract-intercepting-message-processor, mule:abstract-message-processor

Defined: globally in mule-atom.xsd

Used: never

object-to-feed-transformer

Transforms the payload of the message to a {{org.apache.abdera.model.Feed}} instance.

Type: mule:abstractTransformerType

Content: complex, 5 attributes, attr. wildcard, 1 element

Subst.Gr: may substitute for elements: mule:abstract-transformer, mule:abstract-message-processor

Defined: globally in mule-atom.xsd

Used: never

route-filter

Allows ATOM requests to be filtered by request path and HTTP verb.

Type: routeFilterType

Content: complex, 3 attributes, attr. wildcard, 1 element

Subst.Gr:may substitute for elements: mule:abstract-filter, mule:abstract-message-processor

Defined: globally in mule-atom.xsd; see XML source

Used: never

Complex Type Summary

atomComponentType

Content: complex, 2 attributes, attr. wildcard, 8 elements

Defined: globally in mule-atom.xsd

Used: at 1 location

entryBuilderTransformerType

Content: complex, 5 attributes, attr. wildcard, 2 elements

Defined: globally in mule-atom.xsd

Includes: definition of 1 element

Used: at 1 location

entryLastUpdateFilterType

Content: complex, 3 attributes, attr. wildcard, 1 element

Defined: globally in mule-atom.xsd

Includes: definitions of 2 attributes

Used: at 1 location

feedLastUpdateFilterType

Content: complex, 3 [attributes], attr. wildcard, 1 element

Defined: globally in mule-atom.xsd

Includes: definitions of 2 attributes

Used: at 1 location

routeFilterType

Content: complex, 3 attributes, attr. wildcard, 1 element

Defined: globally in mule-atom.xsd

Includes: definitions of 2 attributes

Used: at 1 location

Attributes Group Summary

componentAttributes

Content: 1 attribute

Defined: globally in mule-atom.xsd; see XML source

Includes: definition of 1 attribute

Used: at 1 location

Javadoc API Reference

The Javadoc for this module can be found here:

Maven

The ATOM Module ca be included with the following dependency:

<dependency>
  <groupId>org.mule.modules</groupId>
  <artifactId>mule-module-atom</artifactId>
  <version>3.4.1</version>
</dependency>

Points of Etiquette When Polling Atom Feeds

  1. Make use of HTTP cache. Send Etag and LastModified headers. Recognize 304 Not modified response. This way you can save a lot of bandwidth. Additionally some scripts recognize the LastModified header and return only partial contents (ie. only the two or three newest items instead of all 30 or so).

  2. Don’t poll RSS from services that supports RPC Ping (or other PUSH service, such as PubSubHubBub). That is, if you’re receiving PUSH notifications from a service, you don’t have to poll the data in the standard interval — do it once a day to check if the mechanism still works or not (ping can be disabled, reconfigured, damaged, etc). This way you can fetch RSS only on receiving notification, not every hour or so.

  3. Check the TTL (in RSS) or cache control headers (Expires in ATOM), and don’t fetch until resource expires.

  4. Try to adapt to frequency of new items in each single RSS feed. If in the past week there were only two updates in particular feed, don’t fetch it more than once a day. AFAIR Google Reader does that.

  5. Lower the rate at night hours or other time when the traffic on your site is low.