001: /**
002: * Copyright (c) 2007, Aberystwyth University
003: *
004: * All rights reserved.
005: *
006: * Redistribution and use in source and binary forms, with or without
007: * modification, are permitted provided that the following conditions
008: * are met:
009: *
010: * - Redistributions of source code must retain the above
011: * copyright notice, this list of conditions and the
012: * following disclaimer.
013: *
014: * - Redistributions in binary form must reproduce the above copyright
015: * notice, this list of conditions and the following disclaimer in
016: * the documentation and/or other materials provided with the
017: * distribution.
018: *
019: * - Neither the name of the Centre for Advanced Software and
020: * Intelligent Systems (CASIS) nor the names of its
021: * contributors may be used to endorse or promote products derived
022: * from this software without specific prior written permission.
023: *
024: * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
025: * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
026: * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
027: * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
028: * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
029: * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
030: * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
031: * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
032: * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
033: * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
034: * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
035: * SUCH DAMAGE.
036: */package org.w3.atom;
037:
038: import java.text.ParseException;
039: import java.util.ArrayList;
040: import java.util.Date;
041: import java.util.Iterator;
042: import java.util.List;
043:
044: import nu.xom.Element;
045: import nu.xom.Elements;
046:
047: import org.purl.sword.base.InfoLogger;
048: import org.purl.sword.base.Namespaces;
049: import org.purl.sword.base.SwordElementInterface;
050: import org.purl.sword.base.UnmarshallException;
051: import org.purl.sword.base.XmlElement;
052:
053: /**
054: * Represents an ATOM entry.
055: *
056: * @author Neil Taylor
057: *
058: */
059: public class Entry extends XmlElement implements SwordElementInterface {
060: /**
061: * A list of authors associated with this entry. There can be 0
062: * or more of these elements.
063: */
064: private List<Author> authors;
065:
066: /**
067: * The atom:category data. There can be 0 or more of these elements.
068: * FIXME - this does not accommodate the idea of 'anyForeignElement'
069: */
070: private List<String> categories; // FIXME - needed?
071:
072: /**
073: * A single content element for the Entry.
074: */
075: private Content content;
076:
077: /**
078: * A list of contributors associated with this entry. There can be 0 or
079: * more of these elements.
080: */
081: private List<Contributor> contributors;
082:
083: /**
084: * This is a simplified version. The ID can also have atomCommonAttributes,
085: * but these have not been modelled in this version. The content of
086: * ID is an unconstrained string, which is intended to represent a URI.
087: */
088: private String id;
089:
090: /**
091: * A list of link elements. This can contain 0 or more entries.
092: */
093: private List<Link> links;
094:
095: /**
096: * Simplified version of the atom:published element. This implementation
097: * does not record the general atomCommonAttributes. The date is
098: * taken from an xsd:dateTime value.
099: *
100: * This item is optional.
101: */
102: private Date published;
103:
104: /**
105: * A single, optional, content element for the Entry.
106: * FIXME - this does not cater for the different content types.
107: */
108: private Rights rights;
109:
110: /**
111: * A single, optional, content element for the Entry.
112: */
113: private Source source;
114:
115: /**
116: * A single, optional, summary element for the Entry.
117: * FIXME - this does not cater for the different content types.
118: */
119: private Summary summary;
120:
121: /**
122: * A required title element for the entry.
123: * FIXME - this does not cater for the different content types.
124: */
125: private Title title;
126:
127: /**
128: * The date on which the entry was last updated.
129: */
130: private Date updated;
131:
132: /**
133: * Create a new instance of the class and initialise it.
134: * Also, set the prefix to 'atom' and the local name to 'entry'.
135: */
136: public Entry() {
137: super ("atom", "entry");
138:
139: authors = new ArrayList<Author>();
140: categories = new ArrayList<String>();
141: contributors = new ArrayList<Contributor>();
142: links = new ArrayList<Link>();
143: }
144:
145: /**
146: * Mashall the data stored in this object into Element objects.
147: *
148: * @return An element that holds the data associated with this object.
149: */
150: public Element marshall() {
151: Element entry = new Element(getQualifiedName(),
152: Namespaces.NS_ATOM);
153: entry.addNamespaceDeclaration("sword", Namespaces.NS_SWORD);
154: entry.addNamespaceDeclaration("atom", Namespaces.NS_ATOM);
155:
156: if (id != null) {
157: Element idElement = new Element(getQualifiedName("id"),
158: Namespaces.NS_ATOM);
159: idElement.appendChild(id);
160: entry.appendChild(idElement);
161: }
162:
163: for (Author author : authors) {
164: entry.appendChild(author.marshall());
165: }
166:
167: if (content != null) {
168: entry.appendChild(content.marshall());
169: }
170:
171: for (Author contributor : contributors) {
172: entry.appendChild(contributor.marshall());
173: }
174:
175: for (Link link : links) {
176: entry.appendChild(link.marshall());
177: }
178:
179: if (published != null) {
180: Element publishedElement = new Element(
181: getQualifiedName("published"), Namespaces.NS_ATOM);
182: publishedElement.appendChild(dateToString(published));
183: entry.appendChild(publishedElement);
184: }
185:
186: if (rights != null) {
187: entry.appendChild(rights.marshall());
188: }
189:
190: if (summary != null) {
191: entry.appendChild(summary.marshall());
192: }
193:
194: if (title != null) {
195: entry.appendChild(title.marshall());
196: }
197:
198: if (source != null) {
199: entry.appendChild(source.marshall());
200: }
201:
202: if (updated != null) {
203: Element updatedElement = new Element(
204: getQualifiedName("updated"), Namespaces.NS_ATOM);
205: updatedElement.appendChild(dateToString(updated));
206: entry.appendChild(updatedElement);
207: }
208:
209: Element categoryElement = null;
210: for (String category : categories) {
211: categoryElement = new Element(getQualifiedName("category"),
212: Namespaces.NS_ATOM);
213: categoryElement.appendChild(category);
214: entry.appendChild(categoryElement);
215: }
216:
217: return entry;
218: }
219:
220: /**
221: * Unmarshall the contents of the Entry element into the internal data objects
222: * in this object.
223: *
224: * @param entry The Entry element to process.
225: *
226: * @throws UnmarshallException If the element does not contain an ATOM entry
227: * element, or if there is a problem processing the element or any
228: * subelements.
229: */
230: public void unmarshall(Element entry) throws UnmarshallException {
231: if (!isInstanceOf(entry, localName, Namespaces.NS_ATOM)) {
232: throw new UnmarshallException("Not a " + getQualifiedName()
233: + " element");
234: }
235:
236: try {
237: authors.clear();
238: categories.clear();
239: contributors.clear();
240: links.clear();
241:
242: // retrieve all of the sub-elements
243: Elements elements = entry.getChildElements();
244: Element element = null;
245: int length = elements.size();
246:
247: for (int i = 0; i < length; i++) {
248: element = elements.get(i);
249:
250: if (isInstanceOf(element, "author", Namespaces.NS_ATOM)) {
251: Author author = new Author();
252: author.unmarshall(element);
253: authors.add(author);
254: } else if (isInstanceOf(element, "category",
255: Namespaces.NS_ATOM)) {
256: categories.add(unmarshallString(element));
257: } else if (isInstanceOf(element, "content",
258: Namespaces.NS_ATOM)) {
259: content = new Content();
260: content.unmarshall(element);
261: } else if (isInstanceOf(element, "contributor",
262: Namespaces.NS_ATOM)) {
263: Contributor contributor = new Contributor();
264: contributor.unmarshall(element);
265: contributors.add(contributor);
266: } else if (isInstanceOf(element, "id",
267: Namespaces.NS_ATOM)) {
268: id = unmarshallString(element);
269: } else if (isInstanceOf(element, "link",
270: Namespaces.NS_ATOM)) {
271: Link link = new Link();
272: link.unmarshall(element);
273: links.add(link);
274: } else if (isInstanceOf(element, "published",
275: Namespaces.NS_ATOM)) {
276: published = unmarshallDate(element);
277: } else if (isInstanceOf(element, "rights",
278: Namespaces.NS_ATOM)) {
279: rights = new Rights();
280: rights.unmarshall(element);
281: } else if (isInstanceOf(element, "summary",
282: Namespaces.NS_ATOM)) {
283: summary = new Summary();
284: summary.unmarshall(element);
285: } else if (isInstanceOf(element, "title",
286: Namespaces.NS_ATOM)) {
287: title = new Title();
288: title.unmarshall(element);
289: } else if (isInstanceOf(element, "updated",
290: Namespaces.NS_ATOM)) {
291: updated = unmarshallDate(element);
292: } else if (isInstanceOf(element, "source",
293: Namespaces.NS_ATOM)) {
294: source = new Source();
295: source.unmarshall(element);
296: } else {
297: // unknown element type
298: //counter.other++;
299: }
300: } // for
301: } catch (Exception ex) {
302: InfoLogger.getLogger().writeError(
303: "Unable to parse an element in Entry: "
304: + ex.getMessage());
305: ex.printStackTrace();
306: throw new UnmarshallException(
307: "Unable to parse an element in "
308: + getQualifiedName(), ex);
309: }
310: }
311:
312: /**
313: * Get an iterator for the authors in the Entry.
314: *
315: * @return An iterator.
316: */
317: public Iterator<Author> getAuthors() {
318: return authors.iterator();
319: }
320:
321: /**
322: * Add an author to the Entry.
323: *
324: * @param author The author to add.
325: */
326: public void addAuthors(Author author) {
327: this .authors.add(author);
328: }
329:
330: /**
331: * Clear the list of authors.
332: */
333: public void clearAuthors() {
334: this .authors.clear();
335: }
336:
337: /**
338: * Get an iterator for the categories in this Entry.
339: *
340: * @return An iterator.
341: */
342: public Iterator<String> getCategories() {
343: return categories.iterator();
344: }
345:
346: /**
347: * Add a category.
348: *
349: * @param category the category to add.
350: */
351: public void addCategory(String category) {
352: this .categories.add(category);
353: }
354:
355: /**
356: * Clear the list of categories.
357: */
358: public void clearCategories() {
359: this .categories.clear();
360: }
361:
362: /**
363: * Get the content element for this Entry.
364: *
365: * @return The content element.
366: */
367: public Content getContent() {
368: return content;
369: }
370:
371: /**
372: * Set the content element for this Entry.
373: * @param content
374: */
375: public void setContent(Content content) {
376: this .content = content;
377: }
378:
379: /**
380: * Get a list of contributors.
381: *
382: * @return An iterator.
383: */
384: public Iterator<Contributor> getContributors() {
385: return contributors.iterator();
386: }
387:
388: /**
389: * Add a contributor.
390: *
391: * @param contributor The contributor.
392: */
393: public void addContributor(Contributor contributor) {
394: this .contributors.add(contributor);
395: }
396:
397: /**
398: * Clear the list of contributors.
399: */
400: public void clearContributors() {
401: this .contributors.clear();
402: }
403:
404: /**
405: * Get the ID for this Entry.
406: *
407: * @return The ID.
408: */
409: public String getId() {
410: return id;
411: }
412:
413: /**
414: * Set the ID for this Entry.
415: *
416: * @param id The ID.
417: */
418: public void setId(String id) {
419: this .id = id;
420: }
421:
422: /**
423: * Get the list of links for this Entry.
424: *
425: * @return An iterator.
426: */
427: public Iterator<Link> getLinks() {
428: return links.iterator();
429: }
430:
431: /**
432: * Get the link for this Entry.
433: *
434: * @param link The link.
435: */
436: public void addLink(Link link) {
437: this .links.add(link);
438: }
439:
440: /**
441: * Clear the list of links.
442: */
443: public void clearLinks() {
444: this .links.clear();
445: }
446:
447: /**
448: * Get the published date, expressed as a String.
449: *
450: * @return The date.
451: */
452: public String getPublished() {
453: return dateToString(published);
454: }
455:
456: /**
457: * Set the published date. Converts the date string into a date.
458: * The date should be expressed as a string with the format:
459: * 'yyyy-mm-ddThh:mm:ssZ'.
460: *
461: * @param published The string.
462: *
463: * @throws ParseException, if the date does not match format.
464: */
465: public void setPublished(String published) throws ParseException {
466: this .published = stringToDate(published);
467: }
468:
469: /**
470: * Get the rights for this Entry.
471: * @return The rights.
472: */
473: public Rights getRights() {
474: return rights;
475: }
476:
477: /**
478: * Set the rights for this Entry.
479: *
480: * @param rights The rights.
481: */
482: public void setRights(Rights rights) {
483: this .rights = rights;
484: }
485:
486: /**
487: * Get the source for this Entry.
488: * @return The source.
489: */
490: public Source getSource() {
491: return source;
492: }
493:
494: /**
495: * Set the source for this entry.
496: *
497: * @param source The source.
498: */
499: public void setSource(Source source) {
500: this .source = source;
501: }
502:
503: /**
504: * Get the summary.
505: *
506: * @return The summary.
507: */
508: public Summary getSummary() {
509: return summary;
510: }
511:
512: /**
513: * Set the summary.
514: *
515: * @param summary The summary.
516: */
517: public void setSummary(Summary summary) {
518: this .summary = summary;
519: }
520:
521: /**
522: * Get the title.
523: *
524: * @return The title.
525: */
526: public Title getTitle() {
527: return title;
528: }
529:
530: /**
531: * Set the title.
532: *
533: * @param title The title.
534: */
535: public void setTitle(Title title) {
536: this .title = title;
537: }
538:
539: /**
540: * Get the updated date, expressed as a String.
541: *
542: * @return The date.
543: */
544: public String getUpdated() {
545: return dateToString(updated);
546: }
547:
548: /**
549: * Set the updated date. Converts the date string into a date.
550: * The date should be expressed as a string with the format:
551: * 'yyyy-mm-ddThh:mm:ssZ'.
552: *
553: * @param updated The string.
554: *
555: * @throws ParseException, if the date does not match format.
556: */
557: public void setUpdated(String updated) throws ParseException {
558: this.updated = stringToDate(updated);
559: }
560:
561: }
|