/sitebricks-async/src/main/java/com/google/sitebricks/headless/NettyReplyMaker.java

http://github.com/dhanji/sitebricks · Java · 90 lines · 67 code · 12 blank · 11 comment · 14 complexity · de83584010e7c2146c9a46427350fc60 MD5 · raw file

  1. package com.google.sitebricks.headless;
  2. import com.google.inject.Inject;
  3. import com.google.inject.Injector;
  4. import com.google.inject.Singleton;
  5. import com.google.sitebricks.client.Transport;
  6. import com.google.sitebricks.rendering.Templates;
  7. import org.apache.commons.io.IOUtils;
  8. import org.jboss.netty.buffer.ChannelBuffers;
  9. import org.jboss.netty.handler.codec.http.DefaultHttpResponse;
  10. import org.jboss.netty.handler.codec.http.HttpHeaders.Names;
  11. import org.jboss.netty.handler.codec.http.HttpResponse;
  12. import org.jboss.netty.handler.codec.http.HttpResponseStatus;
  13. import org.jboss.netty.handler.codec.http.HttpVersion;
  14. import org.jboss.netty.util.CharsetUtil;
  15. import java.io.ByteArrayOutputStream;
  16. import java.io.IOException;
  17. import java.io.InputStream;
  18. import java.util.Map.Entry;
  19. /**
  20. * Sits here so it is able to access the internals of ReplyMaker.
  21. *
  22. * @author dhanji@gmail.com (Dhanji R. Prasanna)
  23. */
  24. @Singleton
  25. public class NettyReplyMaker {
  26. private final Injector injector;
  27. @Inject
  28. public NettyReplyMaker(Injector injector) {
  29. this.injector = injector;
  30. }
  31. public <E> HttpResponse populate(Reply<E> o) throws IOException {
  32. // Should be enforced by the Sitebricks page validator.
  33. assert o instanceof ReplyMaker;
  34. ReplyMaker<E> reply = (ReplyMaker<E>) o;
  35. DefaultHttpResponse response = new DefaultHttpResponse(HttpVersion.HTTP_1_1,
  36. HttpResponseStatus.valueOf(reply.status));
  37. Transport transport = injector.getInstance(reply.transport);
  38. if (!reply.headers.isEmpty()) {
  39. for (Entry<String, String> entry : reply.headers.entrySet()) {
  40. response.setHeader(entry.getKey(), entry.getValue());
  41. }
  42. }
  43. // By default we use the content type of the transport.
  44. if (null == reply.contentType) {
  45. response.setHeader(Names.CONTENT_TYPE, transport.contentType());
  46. } else {
  47. response.setHeader(Names.CONTENT_TYPE, reply.contentType);
  48. }
  49. if (null != reply.redirectUri) {
  50. response.setHeader(Names.LOCATION, reply.redirectUri);
  51. return response;
  52. }
  53. // Write the entity data to our output buffer.
  54. if (null != reply.templateKey) {
  55. String output = injector.getInstance(Templates.class).render(reply.templateKey,
  56. reply.entity);
  57. response.setContent(ChannelBuffers.copiedBuffer(output, CharsetUtil.UTF_8));
  58. } else if (null != reply.entity) {
  59. if (reply.entity instanceof InputStream) {
  60. // Buffer the stream and write it, rather than marshalling it through a transport.
  61. // Note this exists for compatibility with the sync model, and can be quite expensive.
  62. InputStream inputStream = (InputStream) reply.entity;
  63. try {
  64. byte[] bytes = IOUtils.toByteArray(inputStream);
  65. response.setContent(ChannelBuffers.copiedBuffer(bytes));
  66. } finally {
  67. inputStream.close();
  68. }
  69. } else {
  70. // TODO(dhanji): This feels wrong to me. We need a better way to obtain the entity type.
  71. ByteArrayOutputStream out = new ByteArrayOutputStream();
  72. transport.out(out, (Class<E>) reply.entity.getClass(), reply.entity);
  73. response.setContent(ChannelBuffers.copiedBuffer(out.toByteArray()));
  74. }
  75. }
  76. return response;
  77. }
  78. }