Overview of Atomictalk

Atomictalk is a Model-View-Controller-inspired, Aspect-Oriented language and platform in which uses a Smalltalk-like syntax to indicate join points within a page, the source of the data collection (Model), the view in which the data should be woven into (View), and a template that should be used for weaving the data via the templates specified controller (Controller).

In addition, at the forefront of the language is the usage of the terms Entity and Page.

Model-View-Controller

Model

As it relates specifically to Atomictalk, a model consists of a collection of one or more resources in which, based on a set of rules (templates), are woven into a view for rendering via the client. Based on AtomPub?, the model also facilitates standard CRUD operations related to these same resources.

View

As it relates specifically to Atomictalk, a view defines the structure of the markup for output via the client as well as any client specific adaptations that should be applied to the view. A view is markup agnostic. (meaning the markup syntax can be rendered into any supported markup, which at current time is (X)HTML, some XAML, and some XUL, though (X)HTML is the only markup language with full support at the moment.)

Controller

As it relates specifically to Atomictalk, a controller is a combination of an XML template and an XSLT weaving engine in which controls the process of weaving together the data collection with a given view as well as facilitating the ability to interact with that data. The desired markup output is specified as part of the configuration, but can be overridden as part of the language syntax.

The Atomictalk Engine

The Atomictalk engine consists of two pieces: A client-side (browser-based) engine written in XSLT 1.0, and a server-side engine written in XSLT 2.0 (though technically speaking it's a modified version of the 1.0 base with only a few XSLT 2.0 specific changes... still more work to do here) and designed to pre-render the various views specified by any given page to minimize the number of document function calls necessary to render the desired output on the client.

TODO: Extend this overview to include greater detail of the rendering engines.

The Atomictalk Language

The Atomictalk language syntax is a cross-breed language system inspired by Smalltalk, while at the same time retaining the well-formed requirement of XML.

Namespaces, Entities, and Pages

Namespaces and Namespace Extensions are used in both the same way and facilitate the same purpose as specified in the XML Namespace specification. However, Atomictalk uses Namespaces and Namespace Extensions in the way that most people naturally expect: If they visit a given URI in their browser, they can expect to find something related to that URI presented to them. For example, if I were to use the URI http://amp.fm/band/pearljam/album/ten as an XML Namespace, the natural tendency is that if I were to visit http://amp.fm/band/pearljam/album/ten I can expect to find something other than a HTTP 404 "Not Found" error code.

As it relates specifically to Atomictalk, an Entity is a Uniform Resource Identifier (URI) which identifies a collection of data related to that Entity within any given system. A Page, on the other hand represents a specified view of that data.

In many ways, the difference between an Entity and a Page can be thought of as follows,

  • An Entity represents a machine readable collection of information related to a particular person, place, or thing. For example, an Atom feed.
  • A Page represents a human readable collection of information related to a particular person, place, or thing. For example, and HTML document.

However, what a page exposes and what it does not is based entirely on the rules specified by the owner of that page. Likewise, while an Entity represents an endpoint related to any given person, place, or thing, querying that endpoint for information does not mean that any or all information that matches this query will be returned. What information is returned and what information is not is solely dependent on the rules specified by the owner of that Entity.

For example, while visiting http://amp.fm/band/pearljam a rule might be set that specifies the Page should only render shows taking place within a certain time span and/or geographical location. In contrast, if querying http://amp.fm/band/pearljam for show information, the scope of shows returned via a query to that Entity may or may not be limited to the same range and/or scope.

Additional rules that may be selectively applied include, but are not limited to,

  • Permissions that allow only a specified group, individual, or list of individuals to view specific content.
  • Content based on user preferences.

Entity Path Segment

The path segment of the Entity URI is used to maintain heirarchal structure within any given system. So, for example, http://amp.fm/band/pearljam/album/ten suggests that the band Pearl Jam has an album called Ten. Using typical Entity Relationship notation, "Pearl Jam is a band", "Ten is an album". By using the path to maintain heirarchal relationship, the Entity URI of http://amp.fm/band/pearljam/album/ten also tells us that "Ten is an album from the band Pearl Jam".

The importance of this relationship becomes more apparent when using namespaces and namespace extensions within the content of any given page. For example, if I have the namespace http://amp.fm/band/pearljam mapped to the extension pj such that xmlns:pj="http://amp.fm/band/pearljam" I can then reference the album Ten within my code as @@pj:album/ten@@. Using this particular syntax, the default action is that of supplying an inline link to http://amp.fm/band/pearljam/album/ten, using a query to this same URI to gain an understanding as to what label should be associated with this link by default. In addition to this, by passing in specific parameters to the Atomictalk engine, instead of rendering an inline link, I can instead specify that I would like to embed a view into my page which lists the tracks from the album, and allows myself or visitors to my page to sample tracks from the album based on the rules specified by the albums owner, Pearl Jam. Those rules may allow for 30 seconds previews to be played inline, the entire album to be streamed at a low bit rate for free, and/or the ability to add the high bit rate streams to my favorites list of which I might pay a premium to gain access to. While the syntax is still under R&D, at present time the following highlights how this is pulled together into something meaningful,

<view:join model="@@pj:album/ten@@" view="@@widget:trackListPlayer|width=100 height=default|@@" controller="@@controller:interactiveAudio@@" />

Of course, if someone would rather shorten up the reference to Pearl Jam's Ten album, they could always map any given extension to the URI http://amp.fm/band/pearljam/album/ten, referencing that extension and then using the path segment to reference a particular track. For example, xmlns:ten="http://amp.fm/band/pearljam/album/ten" could then be used to reference the entire album, or a track within that album by simply using,

<view:join model="@@ten:track/evenflow@@" view="@@widget:rating|style=$@my:style/blue@$@@" controller="@@controller:interactiveAudio@@" />

In the above reference, style=$@my:style/blue@$ introduces the usage of $@namespace:entity/property@$. The $@ is used within the parameter block (the parameter block is everything between | and | just following namespace entity/property reference. In this case, the my namespace is mapped to the owner of the current URI**, specifying to the Atomictalk engine that it should locate the default Entity namespace reference for the current page, query that Entity for the style by the name of blue and then apply the returned value to the rating widget, using the track "Even Flow" from Pearl Jam's Ten album as its data source.

** By default, the my namespace is mapped to the Entity of the current logged in member. In the case of http://member.amp.fm/sylvain, the Atomictalk engine would query the Entity URI http://member.amp.fm/sylvain using the syntax http://member.amp.fm/sylvain:style/blue.

Files and File Structure

Each entity within the system is represented by a path-based URI that matches the directory structure the entity is contained in. Within the root of each folder exists a page folder which contains the following folder structure,

  • Config
  • Controller
  • Model
  • Output
  • Resource
  • View

In addition to the page folder there must be at least one file contained in the root of each entities directory, the at.page file which contains the following,

TODO: FIXME: This has been changed to use the xmlns:my where my is mapped to the current top-level Entity of the page being viewed.

<?xml version="1.0" encoding="UTF-8"?>
<at:page 
    xmlns:at="http://atomictalk.org/" 
    xml:base="http://amp.fm/" 
    view="@@$base:page/view@@" 
    model="@@$base:page/model@@" 
    controller="@@$base:page/controller@@" />

The at.page file represents the model, view, and primary controller that should be used to render the page. While not required, the way Nuxleus handles an at.page file is by dynamically rendering the output into an index.gz file. This allows complete control over what should be rendered on the server and what should be rendered on the client. Ideally the minimum amount of rendering should take place on the client, while at the same time allowing for the greatest level of reusability. What is rendered and save statically on the server and what is left to be dynamically generated on the client can be adjusted by changing the value of the mode attribute contained in the Web.config file. More detail to follow on this particular piece of the Nuxleus web applicaition infrastructure.

In addition to the model, view, and controller attributes each at:page element declaration can contain an xml:base attribute specifying the base URI of the referenced entity. If one does not exist, it is assumed based on the folder heirarchy.

Extending the understanding of the Atomictalk syntax, $base represents the URI contained in the xml:base attribute, or is expanded to the folder heirarchy as specified above. In the regard and using the following example,

view="@@$base:page/view@@"

... the value of @view would be expanded to http://amp.fm/page/view. An HTTP request to http://amp.fm/page/view would return the default file based on order of precedence. At present time view.base and view.gz are the default files served from each folder, view.gz having precedence over view.base. In many cases, view.gz may not exist at all. This is because view.gz represents the pre-rendered and gzipped version of the contents of the view.base file. Using this process ensures that anyone tempted to edit the view.gz file directly will be confronted with nothing but gobbledy gook when using a significant majority of the text editors on the market.

While the handling of the view.base file is left up to each system implementor, as it relates to Nuxleus, view.base (or any *.base file) file is handled by the handler specified in the Web.config file. As mentioned already, the job of the handler is to pre-render the view.base file, compress, and then save it as view.gz. When an HTTP request for http://amp.fm/page/view is made, the web server, which is set to handle requests for view.gz files directly, will look to see if view.gz exists, and if it does handle serving this file directly.

Resources

Sample index.xml File

Standard File Before Pre-Rendering

<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" href="/service/transform/controller/atomictalk/base.xslt"?>
<my:session xmlns:my="http://xameleon.org/my" xmlns:doc="http://atomictalk.org/feed/doc">
    <my:page xmlns:page="http://atomictalk.org/page" xmlns:output="http://atomictalk.org/page/output"
        xmlns:head="http://atomictalk.org/page/output/head" xmlns:body="http://atomictalk.org/page/output/body"
        xmlns:advice="http://atomictalk.org/page/advice">
        <page:config src="/page/config/config.xml">
            <page:advice>
                <advice:page-title>@@domain.label@@</advice:page-title>
                <advice:location.label>amp.fm</advice:location.label>
                <advice:base.theme>993300-999999</advice:base.theme>
                <advice:current-location>@@base-uri@@/@@location@@</advice:current-location>
                <advice:current-location.label>your local scene</advice:current-location.label>
                <advice:map.feed>http://feed.amp.fm/2007/10/20/gigs.atom</advice:map.feed>
            </page:advice>
        </page:config>
        <page:output>
            <page:head src="/page/output/head/base.xml" />
            <page:body src="/page/output/body/search/base.xml" />
        </page:output>
    </my:page>
</my:session>

Non-Typical, Overly Complex Sample With All Referenced Views Woven Into The Output

<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" href="/page/controller/atomictalk/base.xsl"?>
<?oxygen RNGSchema="./page/base.rnc" type="compact"?>
<entity:page xmlns:entity="http://atomictalk.org/entity" xmlns:page="http://atomictalk.org/page"
    xmlns:view="http://atomictalk.org/page/view" xmlns:doc="@@base:doc@@">
    <page:config src="/page/config/config.xml" xmlns:config="http://atomictalk.org/page/config">
        <config:advice xmlns:advice="http://atomictalk.org/page/config/advice">
            <advice:page>
                <advice:title>@@domain.label@@ :: @@date@@</advice:title>
            </advice:page>
            <advice:theme base="@@my:theme@@">
                <advice:base>993300-999999</advice:base>
                <advice:blue>blue</advice:blue>
            </advice:theme>
            <advice:current-location base="@@base-uri@@/@@location@@">
                <advice:label>your local scene</advice:label>
            </advice:current-location>
            <advice:foo>@@foo:bar@@</advice:foo>
        </config:advice>
        <config:session src="@@service:session@@" xmlns:session="http://xameleon.org/session">
            <session:id>@@src:id@@</session:id>
            <session:nonce>@@src:nonce@@</session:nonce>
            <session:openid src="@@current:openid@@" xmlns:openid="http://openid.name/">
                <openid:uri>@@src:uri@@</openid:uri>
                <openid:humanid>@@src:human-name@@</openid:humanid>
            </session:openid>
        </config:session>
    </page:config>
    <page:resource xmlns:resource="http://atomictalk.org/page/resource">
        <resource:my type="service" entity="@@service:ip@@" src="@@current:location@@" xmlns:my="http://member.amp.fm/m.david">
            <my:name scheme="http://member.amp.fm/" label="M. David Peterson" term="myterm">M. David Peterson</my:name>
        </resource:my>
        <resource:lang type="service" entity="@@service:preferences@@" src="@@current:lang@@" />
        <resource:help-support type="page" entity="@@base-uri:support@@" href="@@current@@" />
        <resource:create-new-account type="page" entity="@@base-uri:create-new-account@@" href="@@current@@" />
        <resource:login type="page" entity="@@base-uri:login@@" href="@@current@@" />
    </page:resource>
    <page:model xmlns:model="http://atomictalk.org/page/model">
        <model:foo src="/page/model/collection/foo.collection" />
        <model:bar src="/page/model/collection/bar.collection" />
    </page:model>
    <page:view>
        <view:foo type="form" src="/page/view/form/foo.view" />
        <view:bar type="menu" src="/page/view/menu/bar.view" />
        <view:baz type="list" src="/page/view/list/baz.view" />
        <view:boo type="inline" src="/page/view/content/inline/boo.view" />
        <view:bop type="block" src="/page/view/content/block/boo.view" />
    </page:view>
    <page:controller xmlns:controller="http://atomictalk.org/page/controller">
        <controller:foo src="/page/controller/foo.template" />
        <controller:bar src="/page/controller/bar.template" />
    </page:controller>
    <page:output xmlns:output="http://atomictalk.org/page/output">
        <output:head xmlns:head="http://atomictalk.org/page/output/head">
            <head:title>@@page-title@@</head:title>
            <head:link rel="alternate" type="application/atom+xml" title="Amp.fm ON THE AIR" href="http://dev.amp.fm/ontheair.atom" />
            <head:link rel="alternate" type="application/xml" title="Amp.fm ON THE AIR" href="http://dev.amp.fm/ontheair.atom" />
            <head:link rel="shortcut icon" href="/images/Amp.FM.icon.png" type="image/png" />
            <head:include fileType="css" href="@@static@@/css/base.css" />
            <head:include fileType="css" href="@@static@@/css/transparency.css" />
            <head:include fileType="css" href="@@static-css-browser@@.css" />
            <head:include fileType="css" href="@@static@@/css/base_@@base.theme@@.css" />
        </output:head>
        <output:body xmlns="http://www.w3.org/1999/xhtml" xmlns:output="http://atomictalk.org/page/output"
            xmlns:body="http://atomictalk.org/page/output/body">
            <body:function action="onload" call="@@func:onpageload@@" />
            <body:function action="onunload" call="@@func:onpageunload@@" />
            <body:view>
                <view:container id="main" xmlns:structure="http://atomictalk.org/page/output/body/structure"
                    xmlns:view="http://atomictalk.org/page/view">
                    <view:module id="session" src="/page/view/module/session/controller/base.xml" />
                    <view:module id="header">
                        <view:container id="top-nav">
                            <view:item id="top-login-module" src="/page/view/menu/navigation/top-login.xml" />
                            <view:item id="top-sub-nav-module" src="/page/view/menu/navigation/top-sub-nav.xml" />
                            <view:item id="get-plugged-in" src="/page/view/module/get-plugged-in.xml" />
                            <view:item id="search-module" src="/page/view/search/base.xml" />
                            <view:item id="quick-view-module" src="/page/view/quick-view/base.xml" />
                        </view:container>
                    </view:module>
                    <view:module id="body">
                        <view:container id="content">
                            <view:item id="left" src="@@amp.fm:genre/all/top100:feed@@" />
                            <view:item id="center" src="@@amp.fm:blog:feed@@" />
                            <view:item id="right" src="@@my:friends:feed@@" />
                        </view:container>
                    </view:module>
                    <view:module id="footer">
                        <view:container>
                            <view:item id="control-center" src="/page/view/menu/navigation/bottom-nav/base.xml" />
                        </view:container>
                    </view:module>
                </view:container>
            </body:view>
        </output:body>
    </page:output>
</entity:page>

Page Schema

At present time the following RelaxNG Compact Schema represents the general structure of an Atomictalk index.xml page.

namespace advice = "http://atomictalk.org/page/config/advice"
namespace body = "http://atomictalk.org/page/output/body"
namespace config = "http://atomictalk.org/page/config"
namespace controller = "http://atomictalk.org/page/controller"
namespace entity = "http://atomictalk.org/entity"
namespace head = "http://atomictalk.org/page/output/head"
namespace model = "http://atomictalk.org/page/model"
namespace openid = "http://openid.name/"
namespace output = "http://atomictalk.org/page/output"
namespace page = "http://atomictalk.org/page"
namespace resource = "http://atomictalk.org/page/resource"
namespace session = "http://xameleon.org/session"
namespace structure = "http://atomictalk.org/page/output/body/structure"
namespace view = "http://atomictalk.org/page/view"

start =
    element entity:page {
        element page:config {
            attribute src { text }?,
            element config:advice {
                element advice:* {
                    text?,
                    attribute base { text }?,
                    element advice:* { text }*
                }+
            },
            element config:session {
                attribute src { text },
                element session:id { text },
                element session:nonce { text },
                element session:openid {
                    attribute src { text },
                    element openid:uri { text },
                    element openid:humanid { text }
                }
            }
        },
        element page:resource {
            element resource:* {
                attribute entity { text },
                attribute src { text }?,
                attribute href { text }?,
                attribute type { xsd:NCName },
                element * {
                    text?,
                    attribute scheme { text },
                    attribute label { text },
                    attribute term { text }
                }*
            }+
        },
        element page:model {
            element model:* {
                attribute src { text }
            }+
        },
        element page:view {
            element view:* {
                attribute src { text },
                attribute type { xsd:NCName }
            }+
        },
        element page:controller {
            element controller:* {
                attribute src { text }
            }+
        },
        element page:output {
            element output:head {
                element head:title { text },
                element head:link {
                    attribute href { xsd:anyURI },
                    attribute rel { text },
                    attribute title { text }?,
                    attribute type { text }
                }+,
                element head:include {
                    attribute fileType { xsd:NCName },
                    attribute href { text }
                }+
            },
            element output:body {
                element body:function {
                    attribute action { xsd:NCName },
                    attribute call { text }
                }+,
                element body:view {
                    element view:container {
                        attribute id { xsd:NCName },
                        element view:module {
                            attribute id { xsd:NCName },
                            attribute src { text }?,
                            element view:container {
                                attribute id { xsd:NCName }?,
                                element view:item {
                                    attribute id { xsd:NCName },
                                    attribute src { text }
                                }+
                            }?
                        }+
                    }
                }
            }
        }
    }