/* * AtomProtocol.java * * Created on June 16, 2006, 11:39 AM * * (C) R. Alexander Milowski alex@milowski.com */ package org.exist.atom.modules; import java.io.IOException; import java.io.OutputStream; import java.io.OutputStreamWriter; import java.io.Writer; import java.util.Properties; import org.apache.log4j.Logger; import org.exist.EXistException; import org.exist.atom.Atom; import org.exist.atom.IncomingMessage; import org.exist.atom.OutgoingMessage; import org.exist.collections.Collection; import org.exist.dom.BinaryDocument; import org.exist.dom.DocumentImpl; import org.exist.http.BadRequestException; import org.exist.http.NotFoundException; import org.exist.security.Permission; import org.exist.security.PermissionDeniedException; import org.exist.security.xacml.AccessContext; import org.exist.source.URLSource; import org.exist.storage.DBBroker; import org.exist.storage.lock.Lock; import org.exist.storage.serializers.Serializer; import org.exist.util.serializer.SAXSerializer; import org.exist.util.serializer.SerializerPool; import org.exist.xmldb.XmldbURI; import org.exist.xquery.CompiledXQuery; import org.exist.xquery.XPathException; import org.exist.xquery.XQuery; import org.exist.xquery.XQueryContext; import org.exist.xquery.value.Sequence; import org.xml.sax.SAXException; /** * * @author R. Alexander Milowski */ public class AtomFeeds extends AtomModuleBase implements Atom { protected final static Logger LOG = Logger.getLogger(AtomProtocol.class); static final String FEED_DOCUMENT_NAME = ".feed.atom"; static final XmldbURI FEED_DOCUMENT_URI = XmldbURI.create(FEED_DOCUMENT_NAME); URLSource entryByIdSource; URLSource getFeedSource; /** Creates a new instance of AtomProtocol */ public AtomFeeds() { entryByIdSource = new URLSource(this.getClass().getResource("entry-by-id.xq")); getFeedSource = new URLSource(this.getClass().getResource("get-feed.xq")); } public void doGet(DBBroker broker,IncomingMessage request,OutgoingMessage response) throws BadRequestException,PermissionDeniedException,NotFoundException,EXistException { handleGet(true,broker,request,response); } public void doHead(DBBroker broker,IncomingMessage request,OutgoingMessage response) throws BadRequestException,PermissionDeniedException,NotFoundException,EXistException { handleGet(false,broker,request,response); } protected void handleGet(boolean returnContent, DBBroker broker,IncomingMessage request,OutgoingMessage response) throws BadRequestException,PermissionDeniedException,NotFoundException,EXistException { DocumentImpl resource = null; XmldbURI pathUri = XmldbURI.create(request.getPath()); try { resource = broker.getXMLResource(pathUri, Lock.READ_LOCK); if (resource == null) { String id = request.getParameter("id"); if (id!=null) { id = id.trim(); if (id.length()==0) { id = null; } } // Must be a collection Collection collection = broker.getCollection(pathUri); if (collection != null) { if (!collection.getPermissions().validate(broker.getUser(), Permission.READ)) { throw new PermissionDeniedException("Not allowed to read collection"); } DocumentImpl feedDoc = collection.getDocument(broker,FEED_DOCUMENT_URI); if (feedDoc==null) { throw new BadRequestException("Collection "+request.getPath()+" is not an Atom feed."); } // Return the collection feed String charset = getContext().getDefaultCharset(); if (returnContent) { if (id==null) { response.setStatusCode(200); getFeed(broker,request.getPath(),response); } else { response.setStatusCode(200); getEntryById(broker,request.getPath(),id,response); } } else { response.setStatusCode(204); } } else { throw new NotFoundException("Resource " + request.getPath() + " not found"); } } else { //Do we have permission to read the resource if (!resource.getPermissions().validate(broker.getUser(), Permission.READ)) { throw new PermissionDeniedException("Not allowed to read resource"); } if (returnContent) { response.setStatusCode(200); if (resource.getResourceType() == DocumentImpl.BINARY_FILE) { response.setContentType(resource.getMetadata().getMimeType()); try { OutputStream os = response.getOutputStream(); broker.readBinaryResource((BinaryDocument) resource, os); os.flush(); } catch (IOException ex) { LOG.fatal("Cannot read resource "+request.getPath(),ex); throw new EXistException("I/O error on read of resource "+request.getPath(),ex); } } else { // xml resource Serializer serializer = broker.getSerializer(); serializer.reset(); String charset = getContext().getDefaultCharset(); //Serialize the document try { response.setContentType(resource.getMetadata().getMimeType()+"; charset="+charset); Writer w = new OutputStreamWriter(response.getOutputStream(),charset); serializer.serialize(resource,w); w.flush(); w.close(); } catch (IOException ex) { LOG.fatal("Cannot read resource "+request.getPath(),ex); throw new EXistException("I/O error on read of resource "+request.getPath(),ex); } catch (SAXException saxe) { LOG.warn(saxe); throw new BadRequestException("Error while serializing XML: " + saxe.getMessage()); } } } else { response.setStatusCode(204); } } } finally { if (resource != null) { resource.getUpdateLock().release(Lock.READ_LOCK); } } } public void getEntryById(DBBroker broker,String path,String id,OutgoingMessage response) throws EXistException,BadRequestException { XQuery xquery = broker.getXQueryService(); CompiledXQuery feedQuery = xquery.getXQueryPool().borrowCompiledXQuery(broker,entryByIdSource); XQueryContext context; if (feedQuery==null) { context = xquery.newContext(AccessContext.REST); try { feedQuery = xquery.compile(context, entryByIdSource); } catch (XPathException ex) { throw new EXistException("Cannot compile xquery "+entryByIdSource.getURL(),ex); } catch (IOException ex) { throw new EXistException("I/O exception while compiling xquery "+entryByIdSource.getURL(),ex); } } else { context = feedQuery.getContext(); } context.setStaticallyKnownDocuments(new XmldbURI[] { XmldbURI.create(path).append(AtomProtocol.FEED_DOCUMENT_NAME) }); try { context.declareVariable("id",id); Sequence resultSequence = xquery.execute(feedQuery, null); if (resultSequence.isEmpty()) { throw new BadRequestException("No topic was found."); } String charset = getContext().getDefaultCharset(); response.setContentType("application/atom+xml; charset="+charset); Serializer serializer = broker.getSerializer(); serializer.reset(); try { Writer w = new OutputStreamWriter(response.getOutputStream(),charset); SAXSerializer sax = (SAXSerializer) SerializerPool.getInstance().borrowObject(SAXSerializer.class); Properties outputProperties = new Properties(); sax.setOutput(w, outputProperties); serializer.setProperties(outputProperties); serializer.setSAXHandlers(sax, sax); serializer.toSAX(resultSequence, 1, 1, false); SerializerPool.getInstance().returnObject(sax); w.flush(); w.close(); } catch (IOException ex) { LOG.fatal("Cannot read resource "+path,ex); throw new EXistException("I/O error on read of resource "+path,ex); } catch (SAXException saxe) { LOG.warn(saxe); throw new BadRequestException("Error while serializing XML: " + saxe.getMessage()); } resultSequence.itemAt(0); } catch (XPathException ex) { throw new EXistException("Cannot execute xquery "+entryByIdSource.getURL(),ex); } finally { xquery.getXQueryPool().returnCompiledXQuery(entryByIdSource, feedQuery); } } public void getFeed(DBBroker broker,String path,OutgoingMessage response) throws EXistException,BadRequestException { XQuery xquery = broker.getXQueryService(); CompiledXQuery feedQuery = xquery.getXQueryPool().borrowCompiledXQuery(broker,getFeedSource); XQueryContext context; if (feedQuery==null) { context = xquery.newContext(AccessContext.REST); try { feedQuery = xquery.compile(context, getFeedSource); } catch (XPathException ex) { throw new EXistException("Cannot compile xquery "+getFeedSource.getURL(),ex); } catch (IOException ex) { throw new EXistException("I/O exception while compiling xquery "+getFeedSource.getURL(),ex); } } else { context = feedQuery.getContext(); } context.setStaticallyKnownDocuments(new XmldbURI[] { XmldbURI.create(path).append(AtomProtocol.FEED_DOCUMENT_NAME) }); try { Sequence resultSequence = xquery.execute(feedQuery, null); if (resultSequence.isEmpty()) { throw new BadRequestException("No feed was found."); } String charset = getContext().getDefaultCharset(); response.setContentType("application/atom+xml; charset="+charset); Serializer serializer = broker.getSerializer(); serializer.reset(); try { Writer w = new OutputStreamWriter(response.getOutputStream(),charset); SAXSerializer sax = (SAXSerializer) SerializerPool.getInstance().borrowObject(SAXSerializer.class); Properties outputProperties = new Properties(); sax.setOutput(w, outputProperties); serializer.setProperties(outputProperties); serializer.setSAXHandlers(sax, sax); serializer.toSAX(resultSequence, 1, 1, false); SerializerPool.getInstance().returnObject(sax); w.flush(); w.close(); } catch (IOException ex) { LOG.fatal("Cannot read resource "+path,ex); throw new EXistException("I/O error on read of resource "+path,ex); } catch (SAXException saxe) { LOG.warn(saxe); throw new BadRequestException("Error while serializing XML: " + saxe.getMessage()); } resultSequence.itemAt(0); } catch (XPathException ex) { throw new EXistException("Cannot execute xquery "+getFeedSource.getURL(),ex); } finally { xquery.getXQueryPool().returnCompiledXQuery(getFeedSource, feedQuery); } } }