[r17271]: apps / doc / data / atompub.xml Maximize Restore History

Download this file

atompub.xml    507 lines (498 with data), 24.1 kB

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
<?xml version="1.0" encoding="UTF-8"?>
<!-- $Id: atompub.xml 17271 2012-10-08 15:00:16Z joewiz $ -->
<book>
<bookinfo>
<graphic fileref="logo.jpg"/>
<productname>eXist-db – Open Source Native XML Database</productname>
<title>Atom Publishing Protocol Support</title>
<date>September 2009</date>
<author>
<surname>Milowski</surname>
<firstname>Alex</firstname>
<email>alexmilowski at users.sourceforge.net</email>
</author>
</bookinfo>
<chapter>
<title>A Short Introduction to the Atom Publishing Protocol</title>
<section>
<title>Introduction</title>
<para>The <ulink url="http://www.ietf.org/rfc/rfc5023.txt">Atom
Publishing Protocol</ulink> is a new protocol being developed at the
<ulink url="http://www.ietf.org/">IETF</ulink> as part of their Atom
Publishing Format and Protocol working group that lets you
manipulate Atom feeds over a REST-style HTTP interface. The RFC is still
in draft status but is nearing completion. Though Atom is often associated
with newsfeeds, it can be used for a much wider range of applications.</para>
<para>eXist-db provides an implementation of the <ulink url="http://www.ietf.org/rfc/rfc5023.txt">Atom
Publishing Protocol</ulink> sitting on top of the database. Feed and entry
data is stored into special collections. Our wiki and blog system,
<ulink url="http://code.google.com/p/atomicwiki">AtomicWiki</ulink>, which
powers the <ulink url="http://atomic.exist-db.org/blogs/eXist/">eXist Wiki</ulink>
is completely based on eXist's Atom support.</para>
</section>
<section>
<title>Creating and Manipulating Atom Entries</title>
<para>To create an entry in the feed, you just POST an [atom:]entry
element to the collection url. This creates a new entry in the feed and
possibly returns a new representation of the entry. For example, to
create a simple annotation entry (possibly a blog post), you'd formulate
an [atom:]entry element using the [atom:]content element and post that
to the server.</para>
<example>
<title>Create Entry</title>
<screen>POST /myblog/entries HTTP/1.1
Host: example.org
User- Agent: Thingio/1.0
Content- Type: application/atom+xml
Content- Length: nnn
&lt;?xml version="1.0" ?&gt;
&lt;entry xmlns="http://www.w3.org/2005/Atom"&gt;
&lt;title&gt;Atom-Powered Robots Run Amok&lt;/title&gt;
&lt;id&gt;urn:uuid:1225c695-cfb8-4ebb-aaaa-80da344efa6a&lt;/id&gt;
&lt;updated&gt;2003-12-13T18:30:02Z&lt;/updated&gt;
&lt;author&gt;&lt;name&gt;John Doe&lt;/name&gt;&lt;/author&gt;
&lt;content&gt;Some text.&lt;/content&gt;
&lt;/entry&gt;</screen>
</example>
<note>
<para>It is important to specify the correct Content-Type in the HTTP header.
If the content type is not application/atom+xml, the server will just
store the resource as a document into the existing feed collection and
add an entry to the feed which links to the new resource.</para>
</note>
<para>The server then responds with the created entry, a location header
to the created entry, or both.</para>
<example>
<title>Created Response</title>
<screen>HTTP/1.1 201 Created
Date: Fri, 7 Oct 2005 17:17:11 GMT
Content- Length: nnn
Content- Type: application/atom+xml; charset="utf-8"
Content- Location: http://example.org/edit/first-post.atom
Location: http://example.org/edit/first-post.atom
&lt;?xml version="1.0"?&gt;
&lt;entry xmlns="http://www.w3.org/2005/Atom"&gt;
&lt;title&gt;Atom-Powered Robots Run Amok&lt;/title&gt;
&lt;id&gt;urn:uuid:1225c695-cfb8-4ebb-aaaa-80da344efa6a&lt;/id&gt;
&lt;updated&gt;2003-12-13T18:30:02Z&lt;/updated&gt;
&lt;author&gt;&lt;name&gt;John Doe&lt;/name&gt;&lt;/author&gt;
&lt;content&gt;Some text.&lt;/content&gt;
&lt;link rel="edit"
href="http://example.org/edit/first-post.atom"/&gt;
&lt;/entry&gt;
</screen>
</example>
<para>In the above example response, notice the 'edit' relation link.
This link will let you change this entry in the future. A PUT request on
that link URL will update that entry in the feed. Similarly, a DELETE
request on that link URL will delete the entry.</para>
</section>
<section>
<title>Uploading Resources</title>
<para>Collections can also contain non-atom entry resources that are
also represented by an [atom:]entry in the feed. These are created by a
POST to the same collection URL. The response is an [atom:]entry
element.</para>
<example>
<title>Image Upload</title>
<screen>POST /myblog/fotes HTTP/1.1
Host: example.org
Content- Type: image/png
Content- Length: nnnn
Title: An Atom-Powered Robot
...binary data...</screen>
</example>
<para>In the above request, a title for the entry can be requested when
the resource is created. The server then responds with the created
entry, a location header to the created entry, or both.</para>
<example>
<title>Upload Response</title>
<screen>HTTP/1.1 201 Created
Date: Fri, 7 Oct 2005 17:17:11 GMT
Content- Length: nnn
Content- Type: application/atom+xml; charset="utf-8"
Content- Location: http://example.org/edit/first-post.atom
Location: http://example.org/edit/first-post.atom
&lt;?xml version="1.0"?&gt;
&lt;entry xmlns="http://www.w3.org/2005/Atom"&gt;
&lt;title&gt;A picture of the beach&lt;/title&gt;
&lt;id&gt;urn:uuid:1225c695-cfb8-4ebb-aaaa-80da344efa6a&lt;/id&gt;
&lt;updated&gt;2003-12-13T18:30:02Z&lt;/updated&gt;
&lt;author&gt;&lt;name&gt;John Doe&lt;/name&gt;&lt;/author&gt;
&lt;summary type="text" /&gt;
&lt;content type="image/png"
src="http://example.org/media/img123.png"/&gt;
&lt;link rel="edit"
href="http://example.org/edit/first-post.atom" /&gt;
&lt;link rel="edit-media"
href="http://example.org/edit/img123.png" /&gt;
&lt;/entry&gt;</screen>
</example>
<para>In the above example response, notice the 'edit-media' relation
link in addition to the 'edit' relation link. The 'edit-media' link
relation lets you update the image while the 'edit' link relation lets
you change the entry as in the previous section. Also, a delete on
either editing link relation will delete the resource and its
corresponding entry.</para>
</section>
<section>
<title>Introspection</title>
<para>To get started with an Atom Publishing Protocol enabled service
you need to know the collection URL. A GET request on that collection
URL will return the feed and that same URL is used to create entries.
One way to bootstrap a client and get that collection URL is through
service introspection.</para>
<para>Given a service URL, a GET request will return an XML document
that enumerates the workspaces and collections available to use. This is
a simple document of the following structure:</para>
<example>
<title>An Introspection Document</title>
<programlisting>
<markup>&lt;?xml version="1.0" encoding='utf-8'?&gt;
&lt;service xmlns="http://purl.org/atom/app#"&gt;
&lt;workspace title="Main Site" &gt;
&lt;collection
title="My Blog Entries"
href="http://example.org/reilly/main" /&gt;
&lt;collection
title="Pictures"
href="http://example.org/reilly/pic" &gt;
&lt;accept&gt;image/*&lt;/accept&gt;
&lt;/collection&gt;
&lt;/workspace&gt;
&lt;workspace title="Side Bar Blog"&gt;
&lt;collection title="Remaindered Links"
href="http://example.org/reilly/list" /&gt;
&lt;/workspace&gt;
&lt;/service&gt;</markup>
</programlisting>
</example>
<para>Each 'collection' element represents a feed that can be modified.
The colleciton URL is specified in the 'href' attribute on that
element.</para>
</section>
<section>
<title>Setting Permissions</title>
<para>When creating a feed or entry, you can specify which permissions should
be applied to the newly created resource within eXist. For this, the entry
or feed document should contain an empty element, <sgmltag>exist:permissions</sgmltag>,
in the "exist" namespace.</para>
<synopsis language="xml"><![CDATA[<exist:permissions xmlns:exist="http://exist.sourceforge.net/NS/exist"
owner="myuser" group="mygroup" mode="755"/>]]></synopsis>
<para>where <option>owner</option> and <option>group</option> should be valid database
users/groups and <option>mode</option> is an octal number defining the permissions
to be set. Please refer to the <ulink url="security.xml#octal">Security Guide</ulink>
for further information.</para>
</section>
</chapter>
<chapter>
<title>Atom Services</title>
<section>
<title>Modules</title>
<para>The Atom services are provided by modules loaded into the Atom
service. This service is normally provided at the server's '/atom' path
(e.g. http://localhost:8088/atom/). Every module has a name and to
access the module the name is appended to the atom service path. For
example, for the 'content' module, the URL
http://localhost:8088/atom/content would be used.</para>
<para>Following the module name is a collection or resource path. That
appened path maps to a collection or resource in the database with the
/atom/{name} prefix removed. For example,
'http://localhost:8088/atom/content/myfeed' is the '/myfeed' collection
while 'http://localhost:8088/atom/content' is the root collection of the
database.</para>
<para>The Atom Publishing Protocol makes a distinction between a
collection and the feed that represents it. In eXist, a similar
distinction exists in that a collection is a set of resources and not a
feed. The exception is that the Atom implementation makes one XML
document special and uses that to represent the collection as a
feed.</para>
<para>Currently, if a collection is an also an Atom feed, a document
named '.feed.atom' must exist in the collection. If so, the Atom
interface servlet will treat the collection as a Atom feed that can be
manipulated. If that document does not exist, a module may respond with
a failure status code.</para>
</section>
<section>
<title>The Content Module</title>
<para>Getting the feed is a simple GET request with the "/atom/content"
prefix on the collection path. For example, if you have a collection at
'/my/blog', then the path '/atom/content/my/blog' will return the
feed.</para>
</section>
<section>
<title>The Edit Module</title>
<para>The 'edit' module allows you to create new feeds and manipulate
existing feeds. This module implements the full Atom Publishing protocol
except for the service introspection part.</para>
<para>In addition to implementing the Atom Publishing Protocol, you can
create a manipulate feeds on collections. To create a new collection or
turn an existing collection into a feed, POST an [atom:]feed element to
the collection path with a /atom/edit/ prefix. This will create a new
collection feed using the feed title, etc. specified in the post.</para>
<para>To change the metadata associated with the collection's feed (e.g.
the feed title), make a PUT request to the collection URL with the
updated [atom:]feed element without any [atom:]entry (these will be
ignored). That will change the feed's metadata.</para>
</section>
<section>
<title>The Introspect Module</title>
<para>Service introspection is provided by the 'introspect' module. A
GET request on any collection path prefixed with /atom/introspect will
return a service introspection document.</para>
</section>
<section>
<title>The Query Module</title>
<para>The 'query' module allows you to query your collection's feed by a
POST of an XQuery. The POST is sent to the collection path prefixed with
/atom/query/ and is run against the collection's feed document. This
module is how both the Introspect and Topic modules are implemented. For
example, if you want to generate a feed of all the feeds in all
subcollections, the following query could be sent:</para>
<example>
<title>A Feed Query</title>
<programlisting>
<markup>&lt;feed xmlns="http://www.w3.org/2005/Atom" xmlns:atom="http://www.w3.org/2005/Atom"&gt;
&lt;title&gt;All Feeds Example&lt;/title&gt;
&lt;id&gt;id:all&lt;/id&gt;
{
let $current := substring-before(base-uri(/atom:feed),'/.feed.atom'),
$current-path := substring-after($current,'/db')
for $i in (collection($current)/atom:feed)
let $path := substring-after(substring-before(base-uri($i),'/.feed.atom'),'/db')
return ( &lt;entry&gt;
{
$i/atom:id,
$i/atom:title,
&lt;summary&gt; {
$i/atom:subtitle/@type,
$i/atom:subtitle/node()
}&lt;/summary&gt;,
&lt;link rel="alternate" type="application/atom+xml" href="/atom/edit{$path}"/&gt;
}
&lt;/entry&gt;
)
}
&lt;/feed&gt;</markup>
</programlisting>
</example>
</section>
<section>
<title>The Topic Module</title>
<para>The 'topic' module is an example module that generates a list of
subtopics give a certain feed. A GET request will return a feed with the
collection path's feed, an entry for each ancestor feed, and an entry
for each sub-collection but not any sub-collections of sub-collections.
This is useful for generation feed navigation.</para>
</section>
</chapter>
<chapter>
<title>An Example</title>
<section>
<title>Example Scenario</title>
<para>A blog feed can easily be implemented using the Atom services.
We'll create a blog where all the entries are in the feed as well as any
resources (e.g. images) are also in the same feed.</para>
<para>In this system, we want a /{username}/blog to be the user's blog.
That way we can search against all the user blogs.</para>
</section>
<section>
<title>Setting Up the Blog Feeds</title>
<para>We'll want a top-level blog so we can post queries. This feed can
be empty and is created as:</para>
<example>
<title>Create Users Feed</title>
<screen>POST /atom/edit/users HTTP/1.1
Host: example.org
User- Agent: Thingio/1.0
Content- Type: application/atom+xml
Content- Length: nnn
&lt;?xml version="1.0" ?&gt;
&lt;feed xmlns="http://www.w3.org/2005/Atom"&gt;
&lt;title&gt;All Users&lt;/title&gt;
&lt;/feed&gt;</screen>
</example>
<para>When a user is created, we'll have to post a new [atom:]feed
element to the user directory and blog:</para>
<example>
<title>Create User</title>
<screen>POST /atom/edit/users/johndoe HTTP/1.1
Host: example.org
User- Agent: Thingio/1.0
Content- Type: application/atom+xml
Content- Length: nnn
&lt;?xml version="1.0" ?&gt;
&lt;feed xmlns="http://www.w3.org/2005/Atom"&gt;
&lt;title&gt;User John Doe&lt;/title&gt;
&lt;author&gt;&lt;name&gt;John Doe&lt;/name&gt;&lt;/author&gt;
&lt;/feed&gt;</screen>
</example>
<example>
<title>Create User Blog</title>
<screen>POST /atom/edit/users/johndoe/blog HTTP/1.1
Host: example.org
User- Agent: Thingio/1.0
Content- Type: application/atom+xml
Content- Length: nnn
&lt;?xml version="1.0" ?&gt;
&lt;feed xmlns="http://www.w3.org/2005/Atom"&gt;
&lt;title&gt;John Doe's Blog&lt;/title&gt;
&lt;author&gt;&lt;name&gt;John Doe&lt;/name&gt;&lt;/author&gt;
&lt;/feed&gt;</screen>
</example>
</section>
<section>
<title>Creating Entries</title>
<para>Now a user can post a new entry to their blog:</para>
<example>
<title>Create a New Entry</title>
<screen>POST /atom/edit/users/johndoe/blog HTTP/1.1
Host: example.org
User- Agent: Thingio/1.0
Content- Type: application/atom+xml
Content- Length: nnn
&lt;?xml version="1.0" ?&gt;
&lt;entry xmlns="http://www.w3.org/2005/Atom"&gt;
&lt;title&gt;My First Entry&lt;/title&gt;
&lt;content type='xhtml'&gt;
&lt;div xmlns='http://www.w3.org/1999/xhtml'&gt;
&lt;p&gt;Isn't life grand!?!&lt;/p&gt;
&lt;/div&gt;
&lt;/content&gt;
&lt;/entry&gt;</screen>
</example>
<para>Or do whatever they like with their favorite Atom Publishing
Protocol client.</para>
</section>
<section>
<title>Querying the Blog</title>
<para>A service provider can query their blog to display the entries for
a particular month:</para>
<example>
<title>Find Blog Entries</title>
<screen>POST /atom/query/users/johndoe/blog HTTP/1.1
Host: example.org
User- Agent: Thingio/1.0
Content- Type: application/xquery
Content- Length: nnn
&lt;?xml version="1.0" ?&gt;
&lt;atom:feed xmlns:atom="http://www.w3.org/2005/Atom"&gt;
{
/atom:feed/atom:id,
/atom:feed/atom:title,
/atom:feed/atom:updated,
for $e in (/atom:feed/atom:entry)
where starts-with(string($e/atom:published),"2006-06")
return ( "&amp;#x0a;",$e, "&amp;#x0a;")
}
&lt;/atom:feed&gt;</screen>
</example>
</section>
</chapter>
<chapter>
<title>Configuring the Atom Servlet</title>
<section>
<title>Enabling Atom Services.</title>
<para>The Atom Servlet must be enabled to have Atom services provided by
the standalone configuration. This is done by adding or enabled the Atom
Servlet implementation in server.xml:<example>
<title>Addition for server.xml</title>
<programlisting>
<markup>&lt;servlet enabled="yes"
context="/atom/*"
class="org.exist.atom.http.AtomServlet"/&gt;</markup>
</programlisting>
</example>
</para>
</section>
<section>
<title>Configuration</title>
<para>By default, without any configuration file, all the atom modules
are provided. If there is an atom-services.xml document in the eXist
home directory, that configuration will be used instead. </para>
<example>
<title>atom-services.xml</title>
<programlisting>
<markup>&lt;atom-services xmlns="http://www.exist-db.org/Vocabulary/AtomConfiguration/2006/1/0"&gt;
&lt;module name="edit" class="org.exist.atom.modules.AtomProtocol"/&gt;
&lt;module name="content" class="org.exist.atom.modules.AtomFeeds"/&gt;
&lt;module name="query" query-by-post="true"/&gt;
&lt;module name="topic"&gt;
&lt;method type="GET" query="/org/exist/atom/modules/topic.xq" from-classpath="true"/&gt;
&lt;/module&gt;
&lt;module name="introspect"&gt;
&lt;method type="GET" query="/org/exist/atom/modules/introspect.xq" from-classpath="true"/&gt;
&lt;/module&gt;
&lt;module name="example"&gt;
&lt;method type="GET" query="atom-example.xq"/&gt;
&lt;/module&gt;
&lt;/atom-services&gt;</markup>
</programlisting>
</example>
<section>
<title>Adding a Custom Module</title>
<para>A custom module, implemented in Java, can be configured by
adding a
<code>{http://www.exist-db.org/Vocabulary/AtomConfiguration/2006/1/0}module</code>
element. The 'name' specifies the module name that will be used in the
URL path and the 'class' attribute specifies the implementation class.
This class must implement
<code>com.exist.atom.AtomModule</code>.</para>
</section>
<section>
<title>Adding a Query Module</title>
<para>A query can be registered as module by adding a
<code>{http://www.exist-db.org/Vocabulary/AtomConfiguration/2006/1/0}module</code>
element without the 'class' attribute specified. The 'name' specifies
the module name that will be used in the URL path.</para>
<para>As children of the element, a
<code>{http://www.exist-db.org/Vocabulary/AtomConfiguration/2006/1/0}method</code>
element can be specifed for each HTTP method for which a query should
be associated. This element has three attributes: </para>
<variablelist>
<varlistentry>
<term>type</term>
<listitem>
<para>The HTTP method to which the query should be
associated--must be one of GET, PUT, POST, HEAD, or
DELETE.</para>
</listitem>
</varlistentry>
<varlistentry>
<term>query</term>
<listitem>
<para>A reference to the query source (a relative URL
value).</para>
</listitem>
</varlistentry>
<varlistentry>
<term>from-classpath</term>
<listitem>
<para>A boolean value where 'true' indicates that the query
should be loaded as a resource off the classpath.</para>
</listitem>
</varlistentry>
</variablelist>
</section>
</section>
</chapter>
<chapter>
<title>Extensions</title>
<section>
<title>Setting permissions when creating feeds/entries</title>
<para>When creating a new feed or entry, you can specify
access permissions as well as an owner and owner group
for the new resource. This is done by including a special
<sgmltag>exist:permissions</sgmltag> element in the posted
feed or entry document:</para>
<synopsis><![CDATA[<exist:permissions mode="0755" owner="editor" group="users"/>]]></synopsis>
<para>The <option>mode</option> attribute specifies the permissions to be
assigned to the resource. The attribute value has to be an octal number
or a string describing the permissions to set, using the syntax:</para>
<synopsis>[user|group|other]=[+|-][read|write|update][, ...]</synopsis>
<para>The <option>owner</option> attribute specifies the user which will own
all resources associated to the feed or entry. Parameter <option>group</option>
specifies the user group.</para>
</section>
</chapter>
</book>