AtomPub interface for Guvnor

What is Guvnor AtomPub Interface

 

http://www.atompub.org/ defines a simple interface over HTTP to publish and subscribe to  artifacts (files) and collections of artifacts (services/packages).

 

AtomPub interface serves following purposes:

 

1:  provide "feeds" for people/systems to monitor for changes: For example,  user subscribes to a feed which lists contents of package or user  subscribes to feed which lists changed contents in a package


2.  provide the default remote api to push/pull content and meta data from  the repository. This allows other applications to integrate with Guvnor by accessing repository content via atom pub programmatically.

 

Atom feed/entry schema:

 

A typical Atom entry in Guvnor may look like below:


<entry xmlns="http://www.w3.org/2005/Atom" xml:base="http://localhost:9080/repository/packages/testPackage1/assetes/testRules">
  <id>5a7dc836-32f1-4d97-b593-8f510bfb28c4</id>
  <title type="text">testRule1</title>
  <updated>2008-02-21T20:04:17.481Z</updated>
  <summary type="text">desc of testRule1</summary>

 

  <link href="http://localhost:9080/repository/packages/testPackage1/assets/testRule1"/>

 

  <metadata xmlns="http://overlord/drools/1.0">
    <property name="archived" value="true" />
    <property name="rule-format" value="dsl" />
  </metadata>
  <content type="text">this is the actual content of testRule1</content>
</entry>

 

NOTE:

 

1.  The <metadata> element is an Atom extension element. We will have  pre-defined <metadata> schemas for each type of artifacts that are supported by  Guvnor, for example, a xsd for Drools rules, a xsd for BPEL etc. The <metadata> schema must be extensible/customizable, so  that users can extend or customize the schema to suit their own needs.  The <metadata> serves as tags that users can apply to their  artifacts, it also helps for indexing, querying etc.  Front end GUIs can  also be driven based on this meta data XSDs.

 

2.  The <content> element is used to return artifact conten. In Guvnor, the content of a package or asset can be in text format (or html/xml format) or can be a binary attachement. Thus the <content> can be the actual content in text format, or can be a link pointed to the actual content. The latter is especially useful when the content is binary or its better to be managed separately, for example, we may want  to use a separate URL to manage rules as media types. In this way, we dont have to return the whole content (the size can be big potentially) unless the client requests for it explictly. Using package as an example:

 

return pacakge source directly:

<content type="text" src="the actual content..."/>

 

or return package source as a link

<content type="application/drools-source" src="/repository/packages/testPackage1"/>

 

return package binary:

<content type="application/octet-stream" src="/repository/packages/testPackage1"/>

 

 

3.  If we decide life cycle is an attribute common enough to all artifacts,  then we can add a <lifecycle> extension element, see below:

 

<entry xmlns="http://www.w3.org/2005/Atom" xml:base="http://localhost:9080/repository/packages/testPackage1/assetes/testRules">

  ......

  <metadata xmlns="http://overlord/drools/1.0">

    ....

  </metadata>

  <lifecycle/>
  <content type="text">this is the actual content of testRule1</content>
</entry>

 

 

Inteface Description

 

Even though there are several description languages can be used to define AtomPub intereface, the best way IMO is still through plain documents and examples. So here is how Guvnor AtomPub interface works:

 

 

1. Access packages:

 

The base URL is http://host:portnumber/repository/packages

 

a). Get package list:

 

A HTTP GET request to URL http://host:portnumber/repository/packages with Accept="application/atom+xml" returns a list of packages in the repository in Atom Feed format. An example looks like below:

 

- <atom:feed xmlns:atom="http://www.w3.org/2005/Atom">
<atom:title>Packages</atom:title> 
  <atom:entry>
<atom:title>defaultPackage</atom:title> 

</atom:entry>

 

  <atom:entry>
<atom:title>restPackage1</atom:title> 

</atom:entry>

</atom:feed>

 

This allows users to navigate from packages to a specific package using the atom:link.

 

b). Get a pacakge:

 

A HTTP GET request to URL http://host:portnumber/repository/packages/testPackage1 with Accept="application/atom+xml" returns testPackag1 in the repository in Atom Entry format. An example looks like below:

 

<entry xml:base="http://localhost:9080/repository/packages/testPackage1">

  <id>5a7dc836-32f1-4d97-b593-8f510bfb28c4</id>
  <title type="text">testRule1</title>
  <updated>2008-02-21T20:04:17.481Z</updated>
  <summary type="text">desc of testRule1</summary>

  <link href="http://localhost:9080/repository/packages/testPackage1/assets/testRule1"/>

 

  <metadata xmlns="http://overlord/drools/1.0">
    <property name="archived" value="true" />
    <property name="rule-format" value="dsl" />
  </metadata>

  <lifecycle/>
  <content type="application/octet-stream" src="/repository/packages/testPackage1"/>

</entry>

 

NOTE, above only returns a summary of requested package, the actual content is not returned. The content of a package can be a DRL source (text format) or can be a compiled binary. The client needs to set Accept header properly to let the server knows what content to return. For example:

 

A GET request to http://localhost:9080/repository/packages/package1 with Accept="application/atom+xml" returns an atom entry which is a summary info of that pacakge as well as its meta data.

 

A GET request to http://localhost:9080/repository/packages/package1 with Accept="application/octet-stream" returns the compiled binary.

 

A GET request to http://localhost:9080/repository/packages/package1 with Accept="application/drools-source returns the package source.

 

A GET request to http://localhost:9080/repository/packages/package1 with Accept="application/json" returns a json object which  represents package's summary info as well as meta data, similar to the atom entry.

 

c). Get pacakge snapshot:

 

package snapshot is nothing but a normal  package whose content is frozen. We can always treat package snapshot  as normal pacakge except its content is read-only.

 

d). Create a package (create new package):

 

A HTTP POST request to URL http://host:portnumber/repository/packages with the data:

 

<entry xml:base="http://localhost:9080/repository/packages">

    <title>testPackage1</title>

    <summary>desc1</summary>

</entry>

 

creates a package named testPackage1.

 

e). Create a package (import from DRL):

 

A HTTP POST request to URL http://host:portnumber/repository/packages with the actual DRL file as the inputstream creates a package named testPackage1 whose content is imported from an existing DRL file. NOTE, in order to let the server know the name of the package to be created, client needs to set "Slug" header.

 

f). Update a package:

 

A HTTP PUT request to URL http://host:portnumber/repository/packages/testPackages with the data:

 

<entry xml:base="http://localhost:9080/repository/packages">

   <title>testPackage1</title>

   <summary>desc2</summary>

   <metadata xmlns="http://overlord/drools/1.0">
     <property name="archived" value="true" />
     <property name="rule-format" value="dsl" />
   </metadata>

   <lifecycle/>

</entry>

 

updates testPackage1 summary info in the repository

 

g). Update a package (update its binary attachement):

 

A HTTP PUT request to URL http://host:portnumber/repository/packages/testPackage1 with the actual binary attachement file as the inputstream updates package's binary content.

 

h). Delete a package:


A HTTP DELETE request to URL http://host:portnumber/repository/packages/testPackage1 deletes the package testPackage1

 

i). Compile package: ?


TBD

 

2. Access assets (rules)

 

a). Get asset list under the pacakge:

 

A HTTP GET request to URL http://host:portnumber/repository/packages/testPackage1/assets with Accept="application/atom+xml" returns a list of assets under the testPackage1 in the repository in Atom feed format. An example looks like below:

 

<feed xmlns="http://www.w3.org/2005/Atom" xmlns:xml="http://www.w3.org/XML/1998/namespace" xml:base="http://localhost:9080/repository/packages/testPackage1/assets">

   <title>testPackage1's asset</title>

   <entry xml:base="http://localhost:9080/repository/packages/testPackage1/assets">

     <title>testAsset1</title>

     <link href="http://localhost:9080/repository/packages/testPackage1/assets/testAsset1" />

   </entry>

 

   <entry xml:base="http://localhost:9080/repository/packages/testPackage1/assets">

     <title>testAsset2</title>

     <link href="http://localhost:9080/repository/packages/testPackage1/assets/testAsset2" />

   </entry>

</feed>

 

This allows clients to navigate to a specific asset using the <link> element.

 

b). Get an asset:

 

A GET request to http://host:portnumber/repository/packages/testPackage1/assets/testAsset1 with Accept="application/atom+xml" returns an atom entry which is a summary info of that asset as well as its meta data.

 

A GET request to http://host:portnumber/repository/packages/testPackage1/assets/testAsset1 with Accept="application/octet-stream" returns a binary attachement (if that asset contains a binary attachement).

 

A GET request to http://host:portnumber/repository/packages/testPackage1/assets/testAsset1 with Accept="application/source" returns the asset source in text format (if that asset has a content in text format).

 

A GET request to http://host:portnumber/repository/packages/testPackage1/assets/testAsset1 with Accept="application/json" returns a json object which represents asset summary info as well as meta data, similar to the atom entry.

 

d). Get test scenario:


Test scenario is just a type of asset that belongs to the package. Nothing special.

 

c). Create an asset (create an empty asset):

 

A HTTP POST request to URL http://host:portnumber/repository/packages/package1/assets with the data:

 

<entry xml:base="http://localhost:9080/repository/packages/package1/assets">

   <title>testAsset1</title>

   <summary>desc1</summary>

</entry>

 

creates an asset named testAsset1.

 

d). Create an asset (with content):

 

A HTTP POST request to URL http://host:portnumber/repository/packages/package1/assets with the actual asset content as the inputstream creates an asset named  testAsset1 whose content is imported from the inputstream. NOTE, in order to let the server know the name of the asset to be created, the client needs to set "Slug" header.

 

g). Update an asset:

 

A HTTP PUT request to URL http://host:portnumber/repository/packages/package1/assets/asset1 with the data:

 

<entry xml:base="http://localhost:9080/repository/packages/package1/assets">

   <title>assets1</title>

   <summary>desc2</summary>

</entry>

 

updates asset1 info in the repository

 

h). History and versions:

 

A HTTP GET request to URL http://host:portnumber/repository/packages/testPackage1/assets/myassets/versions  returns a list of versions in Atom feed format.

 

A HTTP GET request to URL http://host:portnumber/repository/packages/{packageName}/assets/{artifactName}/versions/{versionName}   returns an asset with specified version name in Atom Entry format.

 

i). Get attributes/metadata:

 

Some package and asset attributes can map to standard Atom Entry element, such as:

 

<entry xmlns="http://www.w3.org/2005/Atom" xml:base="http://localhost:9080/repository/packages/testPackage1/assetes/testRules">
  <id>5a7dc836-32f1-4d97-b593-8f510bfb28c4</id>
  <title type="text">testRule1</title>
  <updated>2008-02-21T20:04:17.481Z</updated>
  <summary type="text">desc of testRule1</summary>

....

</entry>

 

Other attribute will map to Guvnor specific Atom extension element, such as <metadata> and <lifecycle>. eg:

 

<metadata xmlns="http://overlord/drools/1.0">
    <property name="archived" value="true" />
    <property name="rule-format" value="dsl" />
</metadata>

 

j).Manage the metadata (query available metadata, add new metedata, update metadata definition etc):

 

A HTTP GET request to URL http://host:portnumber/repository/packages/testPackage1/assets/testAsset1/metadatatypes returns a list of metadata types belong to testAsset1 in Atom feed format. An example looks like below:

 

TBD

 

A HTTP POST request to URL http://host:portnumber/repository/packages/testPackage1/assets/testAsset1/metadatatypes

with the data:

 

<entry xml:base="http://localhost:9080/repository/packages/testPackage1/assets/testAsset1/metadatatypes">

   <title>mycustomedTag</title>

   <desc>my own tag</desc>

</entry>

 

creates a metadate named mycustomedTag for testAsset1.



3. Access the repository based on categories:

 

The base URL is http://host:portnumber/repository/categories.

 

Similar to packages, a HTTP GET request to URL http://host:portnumber/repository/categories with Accept="application/atom+xml" returns a list of categories in the repository in Atom Feed format.

 

A HTTP GET request to URL http://host:portnumber/repository/categories/testCategory1/assets with Accept="application/atom+xml" returns a list of assets under the testCategory1 in the repository in Atom feed format.

 

A GET request to http://host:portnumber/repository/categories/testCategory1/assets/testAsset1 with Accept="application/atom+xml" returns an atom entry which is the summary info of that asset as well as its meta data.

 

A GET request to http://host:portnumber/repository/categories/testCategory1/assets/testAsset1 with Accept="application/octet-stream" returns a binary attachment (if that asset contains a binary attachment).

 

A GET request to http://host:portnumber/repository/packages/testPackage1/assets/testAsset1 with Accept="application/source" returns the asset source in text format (if that asset has a content in text format).

 

A GET request to http://host:portnumber/repository/packages/testPackage1/assets/testAsset1 with Accept="application/json" returns a json object which is the summary info of that asset as well as its meta data.

 

 

4. The mapping between Atom Entry element and Drools PackageItem is as below:

 

atom:title   - PackageItem.name

atom:id      - PackageItem.UUID

atom:updated - PackageItem.lastModified

atom:summary - PackageItem.description

 

Other attributes will map to <metadata> extension:

 

<metadata xmlns="http://overlord/drools/1.0">
    <property name="archived" value="true" />
    <property name="rule-format" value="dsl" />
  </metadata>
  <content type="text">this is the actual content of testRule1</content>

 

 

To be defined:

* Collections: packages?

* Binary stuff

* Subscribe for particular categories, statuses etc. - use the URLs

* Paging?

* Querying?


Implementation

 

The easiest way to implement this feature is probably by utilizing a JAX-RS implementation (Such as Apache CXF, RESTEasy etc) together with Apache Abdera. But we are open to all suggestions.

 

BTW I had a similar prototype implementation for SOA repository using CXF and Abdera just FYI: http://anonsvn.jboss.org/repos/guvnor/trunk/atom/