/*
* AtomResource.java
*
* Created on March 27, 2007, 11:48 PM
*
* To change this template, choose Tools | Template Manager
* and open the template in the editor.
*/
package org.atomojo.app;
import java.io.UnsupportedEncodingException;
import java.net.URI;
import java.net.URLEncoder;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.Iterator;
import java.util.List;
import java.util.UUID;
import java.util.logging.Logger;
import org.atomojo.app.db.EntryMedia;
import org.atomojo.app.db.Feed;
import org.infoset.xml.Child;
import org.infoset.xml.Document;
import org.infoset.xml.Element;
import org.infoset.xml.InfosetFactory;
import org.infoset.xml.Item;
import org.infoset.xml.ItemConstructor;
import org.infoset.xml.Name;
import org.infoset.xml.XMLException;
import org.restlet.Application;
import org.restlet.data.MediaType;
import org.restlet.resource.ServerResource;
/**
*
* @author alex
*/
public class AtomResource extends ServerResource {
public static final MediaType ATOM_MEDIA_TYPE = MediaType.valueOf("application/atom+xml");
public static final URI APP_NAMESPACE = URI.create("http://www.w3.org/2007/app");
public static final URI ATOM_NAMESPACE = URI.create("http://www.w3.org/2005/Atom");
public static final Name FEED_NAME = Name.create(ATOM_NAMESPACE,"feed");
public static final Name ENTRY_NAME = Name.create(ATOM_NAMESPACE,"entry");
public static final Name TITLE_NAME = Name.create(ATOM_NAMESPACE,"title");
public static final Name SUMMARY_NAME = Name.create(ATOM_NAMESPACE,"summary");
public static final Name ID_NAME = Name.create(ATOM_NAMESPACE,"id");
public static final Name LINK_NAME = Name.create(ATOM_NAMESPACE,"link");
public static final Name CONTENT_NAME = Name.create(ATOM_NAMESPACE,"content");
public static final Name PUBLISHED_NAME = Name.create(ATOM_NAMESPACE,"published");
public static final Name UPDATED_NAME = Name.create(ATOM_NAMESPACE,"updated");
public static final Name EDITED_NAME = Name.create(APP_NAMESPACE,"edited");
public static final Name AUTHOR_NAME = Name.create(ATOM_NAMESPACE,"author");
public static final Name CATEGORY_NAME = Name.create(ATOM_NAMESPACE,"category");
public static final Name NAME_NAME = Name.create(ATOM_NAMESPACE,"name");
public static final Name CATEGORIES_NAME = Name.create(APP_NAMESPACE,"categories");
public static MediaType XQUERY_TYPE = MediaType.valueOf("application/xquery");
static DateFormat getDateAndTimeFormatter() {
return new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssZ");
}
public static String toXSDDate(Date d) {
DateFormat format = getDateAndTimeFormatter();
String v = format.format(d);
return v.substring(0,22)+':'+v.substring(22);
}
public static Date fromXSDDate(String value)
throws java.text.ParseException
{
if (value.length()<22) {
throw new java.text.ParseException("Truncated dateTime value.",value.length());
}
DateFormat format = getDateAndTimeFormatter();
String wocolon = value.substring(0,22)+value.substring(23);
return format.parse(wocolon);
}
protected Application theApp;
protected Storage storage;
protected Feed feed;
/** Creates a new instance of AtomResource */
public AtomResource(Application app,Feed feed, Storage storage) {
this.theApp = app;
this.feed = feed;
this.storage = storage;
setNegotiated(false);
}
public Feed getFeed() {
return feed;
}
public Storage getStorage() {
return storage;
}
public static Document createFeedDocument(String title,UUID id,Date created)
throws XMLException
{
ItemConstructor constructor = InfosetFactory.getDefaultInfoset().createItemConstructor();
Document doc = constructor.createDocument();
Element top = doc.createDocumentElement(AtomResource.FEED_NAME);
top.addNamespaceBinding("app",APP_NAMESPACE);
top.addElement(TITLE_NAME).addCharacters(title);
top.addElement(ID_NAME).addCharacters("urn:uuid:"+id.toString());
String dateString = toXSDDate(created);
//top.addElement(PUBLISHED_NAME).addCharacters(dateString);
top.addElement(UPDATED_NAME).addCharacters(dateString);
//top.addElement(EDITED_NAME).addCharacters(dateString);
Element link = top.addElement(LINK_NAME);
link.setAttributeValue("rel","self");
link.setAttributeValue("href","");
link = top.addElement(LINK_NAME);
link.setAttributeValue("rel","edit");
link.setAttributeValue("href","");
return doc;
}
public static Document createEntryDocument(String title,UUID id,Date created,String authorName)
throws XMLException
{
ItemConstructor constructor = InfosetFactory.getDefaultInfoset().createItemConstructor();
Document doc = constructor.createDocument();
Element top = doc.createDocumentElement(AtomResource.ENTRY_NAME);
top.addElement(TITLE_NAME).addCharacters(title);
top.addElement(ID_NAME).addCharacters("urn:uuid:"+id.toString());
String dateString = toXSDDate(created);
top.addElement(PUBLISHED_NAME).addCharacters(dateString);
top.addElement(UPDATED_NAME).addCharacters(dateString);
Element edited = top.addElement(EDITED_NAME);
edited.addCharacters(dateString);
edited.setPrefix("app");
Element link = top.addElement(LINK_NAME);
link.setAttributeValue("rel","edit");
link.setAttributeValue("href","./_/"+id);
if (authorName!=null) {
Element author = top.addElement(AUTHOR_NAME);
author.addElement(NAME_NAME).addCharacters(authorName);
}
return doc;
}
public static Document createMediaEntryDocument(String title,UUID id,Date created,String authorName,String href,MediaType type)
throws XMLException
{
Document entryDoc = createEntryDocument(title,id,created,authorName);
Element top = entryDoc.getDocumentElement();
Element link = top.addElement(LINK_NAME);
link.setAttributeValue("rel","edit-media");
link.setAttributeValue("href",href);
Element content = top.addElement(CONTENT_NAME);
content.setAttributeValue("src",href);
content.setAttributeValue("type",type.toString());
return entryDoc;
}
public static void mergeFeedDocument(Document doc,UUID id,Date created,Date modified)
{
boolean idDone = false;
boolean createdDone = false;
boolean modifiedDone = false;
Element feed = doc.getDocumentElement();
List<Child> toRemove = new ArrayList<Child>();
Element linkEdit = null;
for (Child c : feed) {
if (c instanceof Element) {
Element e = (Element)c;
if (e.getName().equals(ID_NAME)) {
idDone = true;
e.clear();
e.addCharacters("urn:uuid:"+id.toString());
/*
} else if (e.getName().equals(PUBLISHED_NAME) && created!=null) {
createdDone = true;
e.clear();
e.addCharacters(toXSDDate(created));
*/
} else if (e.getName().equals(LINK_NAME)) {
String rel = e.getAttributeValue("rel");
if ("edit".equals(rel)) {
linkEdit = e;
} else if ("self".equals(rel)) {
toRemove.add(e);
}
} else if (e.getName().equals(UPDATED_NAME)) {
modifiedDone = true;
e.clear();
e.addCharacters(toXSDDate(modified));
} else if (e.getName().equals(ENTRY_NAME)) {
toRemove.add(e);
}
}
}
if (!modifiedDone) {
feed.addElement(0,UPDATED_NAME).addCharacters(toXSDDate(modified));
}
/*
if (!createdDone && created!=null) {
feed.addElement(0,PUBLISHED_NAME).addCharacters(toXSDDate(created));
}
*/
if (!idDone) {
feed.addElement(0,ID_NAME).addCharacters("urn:uuid:"+id.toString());
}
feed.removeAll(toRemove);
if (linkEdit==null) {
linkEdit = feed.addElement(LINK_NAME);
}
linkEdit.setAttributeValue("rel","edit");
linkEdit.setAttributeValue("href","");
Element selfLink = feed.addElement(LINK_NAME);
selfLink.setAttributeValue("rel","self");
selfLink.setAttributeValue("href","");
}
public static void mergeEntry(Element entry,UUID id,Date created,Date modified,String authorName,EntryMedia media)
{
boolean idDone = false;
boolean createdDone = false;
boolean modifiedDone = false;
boolean editedDone = false;
List<Child> toRemove = new ArrayList<Child>();
Element linkEdit = null;
Element linkEditMedia = null;
Element content = null;
Element author = null;
for (Child c : entry) {
if (c instanceof Element) {
Element e = (Element)c;
if (e.getName().equals(ID_NAME)) {
idDone = true;
e.clear();
e.addCharacters("urn:uuid:"+id.toString());
} else if (e.getName().equals(PUBLISHED_NAME) && created!=null) {
createdDone = true;
/*
e.clear();
e.addCharacters(toXSDDate(created));
*/
} else if (e.getName().equals(UPDATED_NAME)) {
modifiedDone = true;
} else if (e.getName().equals(EDITED_NAME)) {
editedDone = true;
e.clear();
e.setPrefix("app");
e.addCharacters(toXSDDate(modified));
} else if (e.getName().equals(AUTHOR_NAME)) {
author = e;
} else if (e.getName().equals(LINK_NAME)) {
String rel = e.getAttributeValue("rel");
if ("edit".equals(rel)) {
linkEdit = e;
} else if ("self".equals(rel)) {
toRemove.add(e);
} else if ("edit-media".equals(rel)) {
if (media!=null) {
linkEditMedia = e;
} else {
toRemove.add(e);
}
}
} else if (e.getName().equals(CONTENT_NAME)) {
content = e;
}
}
}
if (!modifiedDone) {
entry.addElement(0,UPDATED_NAME).addCharacters(toXSDDate(modified));
}
if (!editedDone) {
Element e = entry.addElement(0,EDITED_NAME);
e.addCharacters(toXSDDate(modified));
e.setPrefix("app");
}
if (!createdDone && created!=null) {
entry.addElement(0,PUBLISHED_NAME).addCharacters(toXSDDate(created));
}
if (!idDone) {
entry.addElement(0,ID_NAME).addCharacters("urn:uuid:"+id.toString());
}
entry.removeAll(toRemove);
if (linkEdit==null) {
linkEdit = entry.addElement(LINK_NAME);
}
linkEdit.setAttributeValue("rel","edit");
linkEdit.setAttributeValue("href","./_/"+id);
if (authorName!=null && author==null) {
author = entry.addElement(AUTHOR_NAME);
author.addElement(NAME_NAME).addCharacters(authorName);
}
if (media!=null) {
if (linkEditMedia==null) {
linkEditMedia = entry.addElement(LINK_NAME);
}
linkEditMedia.setAttributeValue("rel","edit-media");
linkEditMedia.setAttributeValue("href",media.getName());
if (content==null) {
content = entry.addElement(CONTENT_NAME);
}
content.setAttributeValue("type",media.getMediaType().getName());
content.setAttributeValue("src",media.getName());
}
}
public static String getValue(Element e) {
String value = e.getText();
if (value!=null) {
value = value.trim();
if (value.length()==0) {
value = null;
}
}
if (value==null) {
value = e.getAttributeValue("value");
}
return value;
}
public static EntryIndex indexEntry(Logger log,Element entry)
{
EntryIndex index = new EntryIndex();
for (Child c : entry) {
if (c.getType()!=Item.ItemType.ElementItem) {
continue;
}
Element e = (Element)c;
Name name = e.getName();
//Logger.getAnonymousLogger().info("Name: "+name);
if (name.equals(ID_NAME)) {
String value = e.getText().trim();
//Logger.getAnonymousLogger().info("id: "+value);
if (value.startsWith("urn:uuid:")) {
index.setId(UUID.fromString(value.substring(9)));
}
} else if (name.equals(AUTHOR_NAME)) {
Iterator<Element> children = e.getElementsByName(NAME_NAME);
if (children.hasNext()) {
String authorName = children.next().getText().trim();
if (authorName.length()>0) {
index.setAuthorName(authorName);
}
}
} else if (name.equals(CATEGORY_NAME)) {
String scheme = e.getAttributeValue("scheme");
String term = e.getAttributeValue("term");
if (term!=null) {
term = term.trim();
if (term.length()==0) {
term = null;
} else {
try {
term = URLEncoder.encode(term,"UTF-8");
} catch (UnsupportedEncodingException ex) {
log.severe("Cannot encode term due to: "+ex.getMessage());
continue;
}
}
}
if (term==null) {
continue;
}
if (scheme!=null) {
scheme = scheme.trim();
if (scheme.length()==0) {
scheme =null;
}
}
String value = getValue(e);
URI uscheme = null;
if (scheme!=null) {
uscheme = URI.create(scheme);
} else {
uscheme = Categorization.DEFAULT_SCHEME;
}
URI uterm = uscheme.resolve(term).normalize();
if (value==null) {
index.categorize(uterm);
} else {
index.put(uterm,value);
}
}
}
return index;
}
public static FeedIndex indexFeed(Logger log,Element feed)
{
FeedIndex index = new FeedIndex();
for (Child c : feed) {
if (c.getType()!=Item.ItemType.ElementItem) {
continue;
}
Element e = (Element)c;
Name name = e.getName();
if (name.equals(ID_NAME)) {
String value = e.getText().trim();
if (value.startsWith("urn:uuid:")) {
index.setId(UUID.fromString(value.substring(9)));
}
} else if (name.equals(CATEGORY_NAME)) {
String scheme = e.getAttributeValue("scheme");
String term = e.getAttributeValue("term");
if (term!=null) {
term = term.trim();
if (term.length()==0) {
term = null;
} else {
try {
term = URLEncoder.encode(term,"UTF-8");
} catch (UnsupportedEncodingException ex) {
log.severe("Cannot encode term due to: "+ex.getMessage());
continue;
}
}
}
if (term==null) {
continue;
}
String value = getValue(e);
if (scheme!=null) {
scheme = scheme.trim();
if (scheme.length()==0) {
scheme =null;
}
}
URI uscheme = null;
if (scheme!=null) {
uscheme = URI.create(scheme);
} else {
uscheme = Categorization.DEFAULT_SCHEME;
}
URI uterm = uscheme.resolve(term).normalize();
if (value==null) {
index.categorize(uterm);
} else {
index.put(uterm,value);
}
}
}
return index;
}
}