/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
package org.atomojo.app;
import java.io.IOException;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.StringReader;
import java.io.StringWriter;
import java.sql.SQLException;
import java.text.ParseException;
import java.util.Date;
import java.util.Iterator;
import java.util.logging.Level;
import org.atomojo.app.db.DB;
import org.atomojo.app.db.DBIterator;
import org.atomojo.app.db.Entry;
import org.atomojo.app.db.Feed;
import org.infoset.xml.DocumentLoader;
import org.infoset.xml.Element;
import org.infoset.xml.InfosetFactory;
import org.infoset.xml.ItemConstructor;
import org.infoset.xml.ItemDestination;
import org.infoset.xml.Name;
import org.infoset.xml.XMLException;
import org.infoset.xml.filter.RemoveDocumentFilter;
import org.infoset.xml.sax.SAXDocumentLoader;
import org.infoset.xml.util.WriterItemDestination;
import org.restlet.data.CharacterSet;
import org.restlet.data.Form;
import org.restlet.data.MediaType;
import org.restlet.data.Reference;
import org.restlet.data.Status;
import org.restlet.representation.OutputRepresentation;
import org.restlet.representation.Representation;
import org.restlet.representation.StringRepresentation;
import org.restlet.resource.ServerResource;
/**
*
* @author alex
*/
public class UpdatedResource extends ServerResource {
public UpdatedResource() {
setNegotiated(false);
}
public Representation get() {
try {
String path = getRequest().getResourceRef().getRemainingPart();
int q = path.indexOf('?');
if (q>=0) {
path = path.substring(0,q);
}
int h = path.indexOf('#');
if (h>=0) {
path = path.substring(0,h);
}
final DB atomDB = (DB)getContext().getAttributes().get(AtomApplication.DB_ATTR);
Feed feed = null;
if (path.length()>0) {
String [] segments = path.split("/");
feed = atomDB.findFeedByPath(segments);
if (feed==null) {
getResponse().setStatus(Status.CLIENT_ERROR_NOT_FOUND);
return new StringRepresentation("No feed found at path: "+path);
}
}
Form form = getRequest().getResourceRef().getQueryAsForm();
String sinceS = form.getFirstValue("since");
Date since = null;
if (sinceS!=null && sinceS.length()>0) {
try {
since = AtomResource.fromXSDDate(sinceS);
} catch (ParseException ex) {
getResponse().setStatus(Status.CLIENT_ERROR_BAD_REQUEST);
return new StringRepresentation("Bad since value '"+sinceS+"': "+ex.getMessage());
}
}
String limitS = form.getFirstValue("limit");
int limit = 100;
if (limitS!=null && limitS.length()>0) {
try {
limit = Integer.parseInt(limitS);
} catch (NumberFormatException ex) {
getResponse().setStatus(Status.CLIENT_ERROR_BAD_REQUEST);
return new StringRepresentation("Bad limit value '"+limitS+"': "+ex.getMessage());
}
}
String startS = form.getFirstValue("start");
int start = 1;
if (startS!=null && startS.length()>0) {
try {
start = Integer.parseInt(startS);
} catch (NumberFormatException ex) {
getResponse().setStatus(Status.CLIENT_ERROR_BAD_REQUEST);
return new StringRepresentation("Bad start value '"+startS+"': "+ex.getMessage());
}
}
final int startRow = start;
final int limitCount = limit;
final Date sinceMarker = since==null ? new Date() : since;
final Feed target = feed;
return new OutputRepresentation(MediaType.APPLICATION_ATOM) {
public void write(OutputStream os)
throws IOException
{
setCharacterSet(CharacterSet.UTF_8);
try {
String prevRef = null;
if (startRow>1) {
prevRef = getRequest().getResourceRef().toString();
int q = prevRef.indexOf('?');
prevRef = prevRef.substring(0,q);
prevRef += "?";
if (sinceMarker!=null) {
prevRef += "since=";
prevRef += AtomResource.toXSDDate(sinceMarker);
prevRef += "&";
}
prevRef += "start=";
int prevStart = startRow-limitCount;
int prevLimit = limitCount;
if (prevStart<1) {
prevStart = 1;
prevLimit = startRow-1;
}
prevRef += prevStart;
prevRef += "&limit=";
prevRef += prevLimit;
}
String nextRef = getRequest().getResourceRef().toString();
int q = nextRef.indexOf('?');
if (q>=0) {
nextRef = nextRef.substring(0,q);
}
nextRef += "?";
if (sinceMarker!=null) {
nextRef += "since=";
nextRef += AtomResource.toXSDDate(sinceMarker);
nextRef += "&";
}
nextRef += "start=";
nextRef += (startRow+limitCount);
nextRef += "&limit=";
nextRef += limitCount;
DBIterator<Entry> entries = atomDB.getEntriesModifiedBefore(target,sinceMarker,startRow,limitCount);
Form form = getRequest().getResourceRef().getQueryAsForm();
generate(new WriterItemDestination(new OutputStreamWriter(os,"UTF-8"),"UTF-8"),entries,prevRef,nextRef);
entries.finished();
} catch (XMLException ex) {
getContext().getLogger().log(Level.SEVERE,"Cannot serialize metadata feed.",ex);
throw new IOException("Cannot serialize metadata feed.");
} catch (SQLException ex) {
getContext().getLogger().log(Level.SEVERE,"Cannot serialize metadata feed.",ex);
throw new IOException("Cannot serialize metadata feed.");
}
}
};
} catch (SQLException ex) {
getResponse().setStatus(Status.SERVER_ERROR_INTERNAL);
getLogger().log(Level.SEVERE,"Database error during updated resource generation.",ex);
return new StringRepresentation("Cannot get feed from database due to error");
}
}
static void link(ItemConstructor constructor,ItemDestination dest,String rel,String href)
throws XMLException
{
Element linkE = constructor.createElement(AtomResource.LINK_NAME);
linkE.setAttributeValue("rel",rel);
linkE.setAttributeValue("href",href);
linkE.setAttributeValue("type","application/atom+xml");
dest.send(linkE);
dest.send(constructor.createElementEnd(AtomResource.LINK_NAME));
}
static void text(ItemConstructor constructor,ItemDestination dest,Name name,String text)
throws XMLException
{
dest.send(constructor.createElement(name));
dest.send(constructor.createCharacters(text));
dest.send(constructor.createElementEnd(name));
}
public void generate(ItemDestination dest,Iterator<Entry> entries,String prevRef,String nextRef)
throws XMLException
{
//getContext().getLogger().info("Generating feed for term "+term);
ItemConstructor constructor = InfosetFactory.getDefaultInfoset().createItemConstructor();
dest.send(constructor.createDocument());
dest.send(constructor.createElement(AtomResource.FEED_NAME));
dest.send(constructor.createCharacters("\n"));
link(constructor,dest,"self",getRequest().getResourceRef().toString());
if (prevRef!=null) {
link(constructor,dest,"previous",prevRef);
}
link(constructor,dest,"next",nextRef);
dest.send(constructor.createCharacters("\n"));
text(constructor,dest,AtomResource.TITLE_NAME,"Updated");
dest.send(constructor.createCharacters("\n"));
text(constructor,dest,AtomResource.ID_NAME,getRequest().getResourceRef().toString());
dest.send(constructor.createCharacters("\n"));
text(constructor,dest,AtomResource.UPDATED_NAME,AtomResource.toXSDDate(new Date()));
Reference resourceBase = (Reference)getContext().getAttributes().get(AtomApplication.RESOURCE_BASE_ATTR);
App app = (App)getContext().getAttributes().get(AtomApplication.APP_ATTR);
try {
while (entries.hasNext()) {
Entry entry = entries.next();
Feed feed = entry.getFeed();
String feedPath = feed.getPath();
String feedBaseURI = resourceBase.toString()+feedPath;
dest.send(constructor.createCharacters("\n"));
// get the entry representation
Representation rep = app.getStorage().getEntry(feedBaseURI,feedPath,feed.getUUID(),entry.getUUID());
// avoid thread creation because reading an output representation requires a thread
StringWriter sw = new StringWriter();
rep.write(sw);
rep.release();
DocumentLoader loader = new SAXDocumentLoader();
loader.generate(new StringReader(sw.toString()), new RemoveDocumentFilter(dest));
}
} catch (Exception ex) {
throw new XMLException("Exception while getting ancestors.",ex);
}
dest.send(constructor.createCharacters("\n"));
dest.send(constructor.createElementEnd(AtomResource.FEED_NAME));
dest.send(constructor.createDocumentEnd());
}
}