/*
* ProtocolByIdFinder.java
*
* Created on March 27, 2007, 11:09 PM
*
* To change this template, choose Tools | Template Manager
* and open the template in the editor.
*/
package org.atomojo.app;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.Reader;
import java.io.StringWriter;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.net.URLEncoder;
import java.sql.SQLException;
import java.util.UUID;
import java.util.logging.Level;
import org.atomojo.app.db.DB;
import org.atomojo.app.db.Entry;
import org.atomojo.app.db.EntryMedia;
import org.atomojo.app.db.Feed;
import org.infoset.xml.Document;
import org.infoset.xml.DocumentLoader;
import org.infoset.xml.Name;
import org.infoset.xml.XMLException;
import org.infoset.xml.sax.SAXDocumentLoader;
import org.infoset.xml.util.XMLWriter;
import org.restlet.Application;
import org.restlet.Context;
import org.restlet.Request;
import org.restlet.Response;
import org.restlet.data.MediaType;
import org.restlet.data.Method;
import org.restlet.data.Reference;
import org.restlet.data.Status;
import org.restlet.data.Tag;
import org.restlet.representation.Representation;
import org.restlet.resource.Finder;
import org.restlet.resource.ServerResource;
/**
*
* @author alex
*/
public class ProtocolByPathFinder extends Finder {
DB atomDB;
Application theApp;
Reference resourceBase;
DocumentLoader loader = new SAXDocumentLoader();
Storage storage;
App app;
/*
public static String join(String [] values, int start, int length,char delimiter) {
StringBuilder buffer = new StringBuilder();
int end = start+length;
for (int i=start; i<end; i++) {
if (i!=start) {
buffer.append(delimiter);
}
buffer.append(values[i]);
}
return buffer.toString();
}*/
/** Creates a new instance of ProtocolByIdFinder */
public ProtocolByPathFinder(Context context,Application theApp,Reference resourceBase,App app,DB atomDB,Storage storage) {
super(context);
this.theApp = theApp;
this.atomDB = atomDB;
this.resourceBase = resourceBase;
this.storage = storage;
this.app = app;
setTargetClass(ServerResource.class);
}
public ServerResource find(Request request, Response response) {
String uriPath = request.getResourceRef().getRemainingPart();
if (uriPath==null) {
uriPath = request.getResourceRef().getPath();
}
if (uriPath.equals("/")) {
uriPath = "";
}
int q = uriPath.indexOf('?');
if (q>=0) {
uriPath = uriPath.substring(0,q);
}
if (getLogger().isLoggable(Level.FINE)) {
getLogger().fine("by-path, uriPath = '"+uriPath+"'");
}
int uriPathLen = uriPath.length();
String [] segments = uriPath.split("/");
int last = segments.length-1;
String file = null;
if (uriPathLen>0 && uriPath.charAt(uriPathLen-1)!='/' && segments[last].length()>2 && segments[last].indexOf('.')>0) {
file = segments[last];
}
if (file==null) {
// it should be a feed or entry
// test for entry
if (segments.length>=2 && segments[last-1].equals("_")) {
String [] path = new String[segments.length-2];
System.arraycopy(segments,0,path,0,segments.length-2);
UUID entryId = UUID.fromString(segments[last]);
String feedPath = App.join(path,0,path.length,'/')+'/';
try {
Feed f = app.getFeed(feedPath);
if (f!=null) {
try {
Entry entry = f.findEntry(entryId);
if (entry!=null) {
EntryResource r = new EntryResource(theApp,f,entry,storage);
return r;
}
} catch (SQLException ex) {
getContext().getLogger().log(Level.SEVERE,"Failed to retrieve entry at "+entryId+" from the database.",ex);
return new ErrorResource(theApp.getStatusService().getRepresentation(Status.SERVER_ERROR_INTERNAL,request,response));
}
}
return null;
} catch (AppException ex) {
if (ex.getStatus().getCode()==Status.CLIENT_ERROR_NOT_FOUND.getCode()) {
return null;
} else {
getContext().getLogger().log(Level.SEVERE,"Failed to retrieve feed at "+feedPath+" from the database.",ex);
return new ErrorResource(theApp.getStatusService().getRepresentation(Status.SERVER_ERROR_INTERNAL,request,response));
}
}
} else {
try {
Feed f = app.getFeed(uriPath);
if (uriPath.length()>0 && !uriPath.endsWith("/")) {
uriPath += "/";
}
Reference feedResourceRef = new Reference(request.getRootRef().toString()+resourceBase.toString()+uriPath);
FeedResource r = new FeedResource(theApp,f,feedResourceRef,storage);
return r;
} catch (AppException ex) {
if (ex.getStatus().getCode()==Status.CLIENT_ERROR_NOT_FOUND.getCode()) {
// It is possible we have a media entry with no '.' in the name, so test for a media entry
if (segments.length>0) {
String [] path = new String[segments.length-1];
System.arraycopy(segments,0,path,0,segments.length-1);
String feedPath = App.join(path,0,path.length,'/');
file = segments[segments.length-1];
try {
Feed f = app.getFeed(feedPath);
EntryMedia media = f.findEntryResource(file);
if (media!=null) {
MediaResource r = new MediaResource(theApp,f,media,storage);
return r;
} else {
//getLogger().warning("No media resource "+file);
return null;
}
} catch (AppException nex) {
if (ex.getStatus().getCode()==Status.CLIENT_ERROR_NOT_FOUND.getCode()) {
return null;
} else {
getContext().getLogger().log(Level.SEVERE,"Failed to retrieve feed at "+feedPath+" from the database.",nex);
return new ErrorResource(theApp.getStatusService().getRepresentation(Status.SERVER_ERROR_INTERNAL,request,response));
}
} catch (SQLException nex) {
getContext().getLogger().log(Level.SEVERE,"Failed to retrieve entry media "+file+" from feed at "+feedPath+" from the database.",nex);
return new ErrorResource(theApp.getStatusService().getRepresentation(Status.SERVER_ERROR_INTERNAL,request,response));
}
}
return null;
} else {
getContext().getLogger().log(Level.SEVERE,"Failed to retrieve feed at "+uriPath+" from the database.",ex);
return new ErrorResource(theApp.getStatusService().getRepresentation(Status.SERVER_ERROR_INTERNAL,request,response));
}
}
}
} else {
String [] path = new String[segments.length-1];
System.arraycopy(segments,0,path,0,segments.length-1);
String feedPath = App.join(path,0,path.length,'/');
if (file.startsWith("_entry_.")) {
try {
Feed f = app.getFeed(feedPath);
if (f!=null) {
String entryIdS = file.substring(8);
int end = entryIdS.indexOf(".");
if (end<0) {
return null;
}
if (!entryIdS.substring(end).equals(".atom")) {
return null;
}
entryIdS = entryIdS.substring(0,end);
try {
UUID entryId = UUID.fromString(entryIdS);
Entry entry = f.findEntry(entryId);
if (entry!=null) {
EntryResource r = new EntryResource(theApp,f,entry,storage);
return r;
}
} catch (SQLException ex) {
getContext().getLogger().log(Level.SEVERE,"Failed to retrieve entry at "+entryIdS+" from the database.",ex);
return new ErrorResource(theApp.getStatusService().getRepresentation(Status.SERVER_ERROR_INTERNAL,request,response));
} catch (IllegalArgumentException ex) {
return new ErrorResource(theApp.getStatusService().getRepresentation(Status.CLIENT_ERROR_BAD_REQUEST,request,response));
}
}
return null;
} catch (AppException ex) {
if (ex.getStatus().getCode()==Status.CLIENT_ERROR_NOT_FOUND.getCode()) {
return null;
} else {
getContext().getLogger().log(Level.SEVERE,"Failed to retrieve feed at "+feedPath+" from the database.",ex);
return new ErrorResource(theApp.getStatusService().getRepresentation(Status.SERVER_ERROR_INTERNAL,request,response));
}
}
} else if (file.charAt(0)=='.' && file.endsWith(".atom")) {
return new ErrorResource(theApp.getStatusService().getRepresentation(Status.CLIENT_ERROR_BAD_REQUEST,request,response));
} else {
try {
// The media name is already encoded
file = URLDecoder.decode(file,"UTF-8");
file = URLEncoder.encode(file,"UTF-8");
Feed f = app.getFeed(feedPath);
EntryMedia media = f.findEntryResource(file);
if (media!=null) {
MediaResource r = new MediaResource(theApp,f,media,storage);
return r;
} else {
//getLogger().warning("No media resource "+file);
return null;
}
} catch (AppException ex) {
if (ex.getStatus().getCode()==Status.CLIENT_ERROR_NOT_FOUND.getCode()) {
return null;
} else {
getContext().getLogger().log(Level.SEVERE,"Failed to retrieve feed at "+feedPath+" from the database.",ex);
return new ErrorResource(theApp.getStatusService().getRepresentation(Status.SERVER_ERROR_INTERNAL,request,response));
}
} catch (SQLException ex) {
getContext().getLogger().log(Level.SEVERE,"Failed to retrieve entry media "+file+" from feed at "+feedPath+" from the database.",ex);
return new ErrorResource(theApp.getStatusService().getRepresentation(Status.SERVER_ERROR_INTERNAL,request,response));
} catch (UnsupportedEncodingException ex) {
getContext().getLogger().log(Level.SEVERE,"Failed to decode "+file,ex);
return new ErrorResource(theApp.getStatusService().getRepresentation(Status.SERVER_ERROR_INTERNAL,request,response));
}
}
}
}
public void handle(Request request, Response response) {
if (request.getMethod().equals(Method.POST)) {
if (request.getEntity().getMediaType().getName().equals(MediaType.APPLICATION_ATOM_XML.getName())) {
String charset = request.getEntity().getMediaType().getParameters().getValues("charset");
if (charset==null) {
charset = "UTF-8";
}
try {
Reader r = new InputStreamReader(request.getEntity().getStream(),charset);
Document doc = loader.load(r);
r.close();
Name top = doc.getDocumentElement().getName();
if (top.equals(AtomResource.FEED_NAME)) {
String requestPath = request.getResourceRef().getRemainingPart();
if (requestPath==null) {
requestPath = "";
}
if (getLogger().isLoggable(Level.FINE)) {
getLogger().fine("Creating feed at '"+requestPath+"'");
}
try {
Feed f = app.createFeed(requestPath,doc);
response.setStatus(Status.SUCCESS_CREATED);
Representation rep = storage.getFeed(f.getPath(),f.getUUID(),f.getEntries());
if (rep!=null) {
rep.setTag(new Tag(Long.toString(f.getEdited().getTime()),false));
}
response.setEntity(rep);
} catch (AppException ex) {
if (ex.getStatus().equals(Status.SERVER_ERROR_INTERNAL)) {
getLogger().log(Level.SEVERE,ex.getMessage(),ex);
}
response.setStatus(ex.getStatus(),ex.getMessage());
}
} else if (top.equals(AtomResource.ENTRY_NAME)) {
super.handle(new NewEntryRequest(request,doc),response);
} else {
response.setStatus(Status.CLIENT_ERROR_BAD_REQUEST,"Unrecognized document element: "+top);
}
} catch (XMLException ex) {
response.setStatus(Status.CLIENT_ERROR_BAD_REQUEST,"Cannot parse content: "+ex.getMessage());
} catch (Exception ex) {
getContext().getLogger().log(Level.SEVERE,"Fatal exception during post:"+ex.getMessage(),ex);
response.setStatus(Status.CLIENT_ERROR_BAD_REQUEST,"Fatal error "+ex.getMessage());
}
} else {
super.handle(request,response);
}
} else {
super.handle(request,response);
}
}
String serialize(Document doc)
throws XMLException,IOException
{
StringWriter w = new StringWriter();
XMLWriter.writeDocument(doc,w);
return w.toString();
}
}