001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one or more
003: * contributor license agreements. The ASF licenses this file to You
004: * under the Apache License, Version 2.0 (the "License"); you may not
005: * use this file except in compliance with the License.
006: * You may obtain a copy of the License at
007: *
008: * http://www.apache.org/licenses/LICENSE-2.0
009: *
010: * Unless required by applicable law or agreed to in writing, software
011: * distributed under the License is distributed on an "AS IS" BASIS,
012: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013: * See the License for the specific language governing permissions and
014: * limitations under the License. For additional information regarding
015: * copyright in this work, please see the NOTICE file in the top level
016: * directory of this distribution.
017: */
018: package org.apache.roller.webservices.atomprotocol;
019:
020: import java.util.ArrayList;
021: import java.util.Iterator;
022: import java.util.LinkedHashSet;
023: import java.util.List;
024: import java.util.Set;
025:
026: import org.jdom.Document;
027: import org.jdom.Element;
028: import org.jdom.Namespace;
029:
030: /**
031: * This class models an Atom Ublishing Protocol Service Document.
032: * <p />
033: * Based on: draft-ietf-atompub-protocol-10.txt
034: * <p />
035: * Designed to be Roller independent.
036: */
037: /*
038:
039: namespace app = "http://purl.org/atom/app#"
040: start = appService
041:
042: appService =
043: element app:service {
044: appCommonAttributes,
045: ( appWorkspace+
046: & extensionElement* )
047: }
048:
049: For example:
050:
051: <?xml version="1.0" encoding='utf-8'?>
052: <service xmlns="http://purl.org/atom/app#"
053: xmlns:atom="http://www.w3.org/2005/Atom">
054: <workspace>
055: <atom:title>Main Site</atom:title>
056: <collection
057: href="http://example.org/reilly/main" >
058: <atom:title>My Blog Entries</atom:title>
059: <categories
060: href="http://example.com/cats/forMain.cats" />
061: </collection>
062: <collection
063: href="http://example.org/reilly/pic" >
064: <atom:title>Pictures</atom:title>
065: <accept>image/*</accept>
066: </collection>
067: </workspace>
068: <workspace>
069: <atom:title>Side Bar Blog</atom:title>
070: <collection
071: href="http://example.org/reilly/list" >
072: <atom:title>Remaindered Links</atom:title>
073: <accept>entry</accept>
074: <categories fixed="yes">
075: <atom:category
076: scheme="http://example.org/extra-cats/"
077: term="joke" />
078: <atom:category
079: scheme="http://example.org/extra-cats/"
080: term="serious" />
081: </categories>
082: </collection>
083: </workspace>
084: </service>
085: */
086: public class AtomService {
087: public static final Namespace ns = Namespace.getNamespace("app",
088: "http://purl.org/atom/app#");
089: public static final Namespace atomns = Namespace.getNamespace(
090: "atom", "http://www.w3.org/2005/atom");
091:
092: private List workspaces = new ArrayList();
093:
094: public AtomService() {
095: }
096:
097: public void addWorkspace(AtomService.Workspace workspace) {
098: workspaces.add(workspace);
099: }
100:
101: public List getWorkspaces() {
102: return workspaces;
103: }
104:
105: public void setWorkspaces(List workspaces) {
106: this .workspaces = workspaces;
107: }
108:
109: /**
110: * This class models an Atom workspace.
111: * @author Dave Johnson
112: */
113: /*
114: appWorkspace =
115: element app:workspace {
116: appCommonAttributes,
117: ( appCollection*
118: & extensionElement* )
119: }
120: atomTitle = element atom:title { atomTextConstruct }
121: */
122: public static class Workspace {
123: private String title = null;
124: private String titleType = null; // may be TEXT, HTML, XHTML
125: private Set collections = new LinkedHashSet();
126:
127: public Workspace() {
128: }
129:
130: /** Iterate over collections in workspace */
131: public Iterator getCollections() {
132: return collections.iterator();
133: }
134:
135: /** Add new collection to workspace */
136: public void addCollection(AtomService.Collection col) {
137: collections.add(col);
138: }
139:
140: /** Workspace must have a human readable title */
141: public String getTitle() {
142: return title;
143: }
144:
145: public void setTitle(String title) {
146: this .title = title;
147: }
148:
149: public String getTitleType() {
150: return titleType;
151: }
152:
153: public void setTitleType(String titleType) {
154: this .titleType = titleType;
155: }
156: }
157:
158: /**
159: * This class models an Atom workspace collection.
160: */
161: /*
162: appCollection =
163: element app:collection {
164: appCommonAttributes,
165: attribute href { atomURI },
166: ( appAccept?
167: & appCategories*
168: & extensionElement* )
169: }
170: */
171: public static class Collection {
172: private String title = null;
173: private String titleType = null; // may be TEXT, HTML, XHTML
174: private String accept = "entry";
175: private String listTemplate = null;
176: private String href = null;
177: private Set categories = new LinkedHashSet(); // of Categories objects
178:
179: public Collection() {
180: }
181:
182: /**
183: * Comma separated list of media-ranges accepted by collection
184: * or "entry" to indicate Atom entries only. Leaving null will
185: * default to entries only.
186: */
187: public String getAccept() {
188: return accept;
189: }
190:
191: public void setAccept(String accept) {
192: this .accept = accept;
193: }
194:
195: /** The URI of the collection */
196: public String getHref() {
197: return href;
198: }
199:
200: public void setHref(String href) {
201: this .href = href;
202: }
203:
204: /** Must have human readable title */
205: public String getTitle() {
206: return title;
207: }
208:
209: public void setTitle(String title) {
210: this .title = title;
211: }
212:
213: public String getTitleType() {
214: return titleType;
215: }
216:
217: public void setTitleType(String titleType) {
218: this .titleType = titleType;
219: }
220:
221: /** Workspace can have multiple Categories objects */
222: public void addCategories(Categories cats) {
223: categories.add(cats);
224: }
225:
226: /** Iterate over Categories objects in Collection */
227: public Iterator getCategories() {
228: return categories.iterator();
229: }
230: }
231:
232: /**
233: * Categories object contains Category objects
234: */
235: /*
236: appInlineCategories =
237: element app:categories {
238: attribute fixed { "yes" | "no" }?,
239: attribute scheme { atomURI }?,
240: (atomCategory*)
241: }
242: */
243: public static class Categories {
244: private Set categories = new LinkedHashSet(); // of Category objects
245: private String scheme = null;
246: private boolean fixed = false;
247:
248: /** Add category list of those specified*/
249: public void addCategory(Category cat) {
250: categories.add(cat);
251: }
252:
253: /** Iterate over Category objects */
254: public Iterator getCategories() {
255: return categories.iterator();
256: }
257:
258: /** True if clients MUST use one of the categories specified */
259: public boolean isFixed() {
260: return fixed;
261: }
262:
263: /** True if clients MUST use one of the categories specified */
264: public void setFixed(boolean fixed) {
265: this .fixed = fixed;
266: }
267:
268: /** Category URI scheme to use for Categories without a scheme */
269: public String getScheme() {
270: return scheme;
271: }
272:
273: /** Category URI scheme to use for Categories without a scheme */
274: public void setScheme(String scheme) {
275: this .scheme = scheme;
276: }
277: }
278:
279: /**
280: * Represents an <atom:category> object
281: */
282: /*
283: atomCategory =
284: element atom:category {
285: atomCommonAttributes,
286: attribute term { text },
287: attribute scheme { atomURI }?,
288: attribute label { text }?,
289: undefinedContent
290: }
291: */
292: public static class Category {
293: private String term;
294: private String scheme;
295: private String label;
296:
297: public String getTerm() {
298: return term;
299: }
300:
301: public void setTerm(String term) {
302: this .term = term;
303: }
304:
305: public String getScheme() {
306: return scheme;
307: }
308:
309: public void setScheme(String scheme) {
310: this .scheme = scheme;
311: }
312:
313: public String getLabel() {
314: return label;
315: }
316:
317: public void setLabel(String label) {
318: this .label = label;
319: }
320: }
321:
322: /** Deserialize an Atom service XML document into an object */
323: public static AtomService documentToService(Document document) {
324: AtomService service = new AtomService();
325: Element root = document.getRootElement();
326: List spaces = root.getChildren("workspace", ns);
327: Iterator iter = spaces.iterator();
328: while (iter.hasNext()) {
329: Element e = (Element) iter.next();
330: service.addWorkspace(AtomService.elementToWorkspace(e));
331: }
332: return service;
333: }
334:
335: /** Serialize an AtomService object into an XML document */
336: public static Document serviceToDocument(AtomService service) {
337: Document doc = new Document();
338: Element root = new Element("service", ns);
339: doc.setRootElement(root);
340: Iterator iter = service.getWorkspaces().iterator();
341: while (iter.hasNext()) {
342: AtomService.Workspace space = (AtomService.Workspace) iter
343: .next();
344: root.addContent(AtomService.workspaceToElement(space));
345: }
346: return doc;
347: }
348:
349: /** Deserialize a Atom workspace XML element into an object */
350: public static AtomService.Workspace elementToWorkspace(
351: Element element) {
352: AtomService.Workspace space = new AtomService.Workspace();
353:
354: Element titleElem = element.getChild("title", atomns);
355: space.setTitle(titleElem.getText());
356: if (titleElem.getAttribute("type", atomns) != null) {
357: space.setTitleType(titleElem.getAttribute("type", atomns)
358: .getValue());
359: }
360:
361: List collections = element.getChildren("collection", ns);
362: Iterator iter = collections.iterator();
363: while (iter.hasNext()) {
364: Element e = (Element) iter.next();
365: space.addCollection(AtomService.elementToCollection(e));
366: }
367: return space;
368: }
369:
370: /** Serialize an AtomService.Workspace object into an XML element */
371: public static Element workspaceToElement(Workspace space) {
372: Element element = new Element("workspace", ns);
373:
374: Element title = new Element("title", atomns);
375: title.setText(space.getTitle());
376: element.addContent(title);
377: if (space.getTitleType() != null
378: && !space.getTitleType().equals("TEXT")) {
379: element.setAttribute("type", space.getTitleType(), atomns);
380: }
381:
382: Iterator iter = space.getCollections();
383: while (iter.hasNext()) {
384: AtomService.Collection col = (AtomService.Collection) iter
385: .next();
386: element.addContent(collectionToElement(col));
387: }
388: return element;
389: }
390:
391: /** Deserialize an Atom service collection XML element into an object */
392: public static AtomService.Collection elementToCollection(
393: Element element) {
394: AtomService.Collection collection = new AtomService.Collection();
395: collection.setHref(element.getAttribute("href").getValue());
396:
397: Element titleElem = element.getChild("title", atomns);
398: if (titleElem != null) {
399: collection.setTitle(titleElem.getText());
400: if (titleElem.getAttribute("type", atomns) != null) {
401: collection.setTitleType(titleElem.getAttribute("type",
402: atomns).getValue());
403: }
404: }
405:
406: Element memberType = element.getChild("accept", ns);
407: if (memberType != null) {
408: collection.setAccept(memberType.getText());
409: }
410:
411: // Loop to parse <app:categories> element to Categories objects
412: List catsElems = element.getChildren("categories", ns);
413: for (Iterator catsIter = catsElems.iterator(); catsIter
414: .hasNext();) {
415: Element catsElem = (Element) catsIter.next();
416: Categories cats = new Categories();
417: if ("yes".equals(catsElem.getAttribute("fixed", ns))) {
418: cats.setFixed(true);
419: }
420: // Loop to parse <atom:category> elemenents to Category objects
421: List catElems = catsElem.getChildren("category", atomns);
422: for (Iterator catIter = catElems.iterator(); catIter
423: .hasNext();) {
424: Element catElem = (Element) catIter.next();
425: Category cat = new Category();
426: cat.setTerm(catElem.getAttributeValue("term", atomns));
427: cat
428: .setLabel(catElem.getAttributeValue("label",
429: atomns));
430: cat.setScheme(catElem.getAttributeValue("scheme",
431: atomns));
432: cats.addCategory(cat);
433: }
434: collection.addCategories(cats);
435: }
436: return collection;
437: }
438:
439: /** Serialize an AtomService.Collection object into an XML element */
440: public static Element collectionToElement(
441: AtomService.Collection collection) {
442: Element element = new Element("collection", ns);
443: element.setAttribute("href", collection.getHref());
444:
445: Element title = new Element("title", atomns);
446: title.setText(collection.getTitle());
447: element.addContent(title);
448: if (collection.getTitleType() != null
449: && !collection.getTitleType().equals("TEXT")) {
450: element.setAttribute("type", collection.getTitleType(),
451: atomns);
452: }
453:
454: // Loop to create <app:categories> elements
455: for (Iterator it = collection.getCategories(); it.hasNext();) {
456: Categories cats = (Categories) it.next();
457: Element catsElem = new Element("categories", ns);
458: catsElem.setAttribute("fixed", cats.isFixed() ? "yes"
459: : "no", ns);
460: if (cats.getScheme() != null) {
461: catsElem.setAttribute("scheme", cats.getScheme(), ns);
462: }
463: // Loop to create <atom:category> elements
464: for (Iterator catIter = cats.getCategories(); catIter
465: .hasNext();) {
466: Category cat = (Category) catIter.next();
467: Element catElem = new Element("category", atomns);
468: catElem.setAttribute("term", cat.getTerm(), atomns);
469: if (cat.getScheme() != null) { // optional
470: catElem.setAttribute("scheme", cat.getScheme(),
471: atomns);
472: }
473: if (cat.getLabel() != null) { // optional
474: catElem.setAttribute("label", cat.getLabel(),
475: atomns);
476: }
477: catsElem.addContent(catElem);
478: }
479: element.addContent(catsElem);
480: }
481:
482: Element memberType = new Element("accept", ns);
483: memberType.setText(collection.getAccept());
484: element.addContent(memberType);
485:
486: return element;
487: }
488: }
|