package org.atomnuke.servlet;
import com.rackspace.papi.commons.util.io.RawInputStreamReader;
import java.io.IOException;
import java.util.GregorianCalendar;
import java.util.UUID;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.xml.datatype.DatatypeConfigurationException;
import javax.xml.datatype.DatatypeFactory;
import javax.xml.datatype.XMLGregorianCalendar;
import org.atomnuke.atom.io.AtomReadException;
import org.atomnuke.atom.io.AtomReaderFactory;
import org.atomnuke.atom.io.ReaderResult;
import org.atomnuke.atom.io.reader.sax.SaxAtomReaderFactory;
import org.atomnuke.atom.model.builder.ContentBuilder;
import org.atomnuke.atom.model.builder.EntryBuilder;
import org.atomnuke.atom.model.builder.IdBuilder;
import org.atomnuke.atom.model.builder.UpdatedBuilder;
import org.atomnuke.util.source.QueueSource;
import org.atomnuke.lifecycle.InitializationException;
import org.atomnuke.util.io.LimitedReadInputStream;
import org.atomnuke.util.io.ReadLimitException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.eclipse.jetty.http.HttpStatus;
/**
*
* @author zinic
*/
public class AtomSinkServlet extends HttpServlet {
private static final Logger LOG = LoggerFactory.getLogger(AtomSinkServlet.class);
private static final DatatypeFactory DATATYPE_FACTORY;
static {
try {
DATATYPE_FACTORY = DatatypeFactory.newInstance();
} catch (DatatypeConfigurationException dce) {
LOG.error(dce.getMessage(), dce);
throw new RuntimeException("Unable to initialize a datatype factory for XML dates.");
}
}
private final AtomReaderFactory atomReaderFactory;
private final QueueSource queueSource;
public AtomSinkServlet(QueueSource queueSource) throws InitializationException {
this.queueSource = queueSource;
atomReaderFactory = new SaxAtomReaderFactory();
}
private static void notAllowed(HttpServletResponse resp) {
resp.setStatus(HttpStatus.METHOD_NOT_ALLOWED_405);
resp.addHeader("ALLOW", "POST");
}
private void process(HttpServletRequest req, HttpServletResponse resp) throws IOException {
final String contentType = req.getHeader("Content-Type");
if (contentType == null || !contentType.equalsIgnoreCase("application/atom+xml")) {
final String content = new String(RawInputStreamReader.instance().readFully(req.getInputStream()));
final EntryBuilder newEntry = new EntryBuilder();
newEntry.setContent(new ContentBuilder().setType(contentType).setValue(content).build());
queueSource.put(newEntry.build());
} else {
try {
final ReaderResult readerResult = atomReaderFactory.getInstance().read(new LimitedReadInputStream(req.getInputStream(), 5242880));
if (readerResult.getEntry() != null) {
final XMLGregorianCalendar cal = DATATYPE_FACTORY.newXMLGregorianCalendar((GregorianCalendar) GregorianCalendar.getInstance());
final EntryBuilder newEntry = new EntryBuilder(readerResult.getEntry());
newEntry.setId(new IdBuilder().setValue(UUID.randomUUID().toString()).build());
newEntry.setUpdated(new UpdatedBuilder().setValue(cal.toXMLFormat()).build());
queueSource.put(newEntry.build());
resp.setStatus(HttpStatus.ACCEPTED_202);
} else {
resp.setStatus(HttpStatus.BAD_REQUEST_400);
resp.getWriter().append("Request entity must be an Entry.");
}
} catch (AtomReadException ape) {
LOG.error(ape.getMessage(), ape);
final Throwable cause = ape.getCause();
if (cause instanceof ReadLimitException) {
resp.setStatus(HttpStatus.REQUEST_ENTITY_TOO_LARGE_413);
resp.getWriter().append("Request entity too large. The limit is 5MB.");
} else if (cause instanceof IOException) {
resp.setStatus(HttpStatus.INTERNAL_SERVER_ERROR_500);
resp.getWriter().append("Unable to read request entity. Reason: " + cause.getMessage());
} else {
resp.setStatus(HttpStatus.BAD_REQUEST_400);
resp.getWriter().append("Request entity not well formed. Reason: " + ape.getMessage());
}
}
}
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
process(req, resp);
}
@Override
protected void doPut(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
process(req, resp);
}
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
notAllowed(resp);
}
@Override
protected void doHead(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
notAllowed(resp);
}
@Override
protected void doDelete(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
notAllowed(resp);
}
@Override
protected void doOptions(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
notAllowed(resp);
}
@Override
protected void doTrace(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
notAllowed(resp);
}
}