PageRenderTime 39ms CodeModel.GetById 31ms app.highlight 4ms RepoModel.GetById 1ms app.codeStats 0ms

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