/sitebricks/src/main/java/com/google/sitebricks/headless/ReplyMaker.java
http://github.com/dhanji/sitebricks · Java · 239 lines · 184 code · 41 blank · 14 comment · 55 complexity · 625bc77963dad633ba6b75f6142487cd MD5 · raw file
- package com.google.sitebricks.headless;
- import com.google.common.base.Preconditions;
- import com.google.common.collect.Maps;
- import com.google.common.io.ByteStreams;
- import com.google.inject.Injector;
- import com.google.inject.Key;
- import com.google.sitebricks.client.Transport;
- import com.google.sitebricks.client.transport.Text;
- import com.google.sitebricks.rendering.Strings;
- import com.google.sitebricks.rendering.Templates;
- import javax.servlet.http.HttpServletRequest;
- import javax.servlet.http.HttpServletResponse;
- import java.io.IOException;
- import java.io.InputStream;
- import java.util.Map;
- /**
- * A builder implementation of the Reply interface.
- */
- class ReplyMaker<E> extends Reply<E> {
- // By default, we cool.
- int status = HttpServletResponse.SC_OK;
- String contentType;
- String redirectUri;
- Map<String, String> headers = Maps.newHashMap();
- Key<? extends Transport> transport = Key.get(Text.class);
- E entity;
- Class<?> templateKey;
- public ReplyMaker(E entity) {
- this.entity = entity;
- }
- @Override
- public Reply<E> seeOther(String uri) {
- redirectUri = uri;
- status = HttpServletResponse.SC_MOVED_PERMANENTLY;
- return this;
- }
- @Override
- public Reply<E> seeOther(String uri, int statusCode) {
- Preconditions.checkArgument(statusCode >= 300 && statusCode < 400,
- "Redirect statuses must be between 300-399");
- redirectUri = uri;
- status = statusCode;
- return this;
- }
- @Override
- public Reply<E> type(String mediaType) {
- Strings.nonEmpty(mediaType, "Media type cannot be null or empty");
- this.contentType = mediaType;
- return this;
- }
- @Override
- public Reply<E> headers(Map<String, String> headers) {
- this.headers.putAll(headers);
- return this;
- }
- @Override
- public Reply<E> notFound() {
- status = HttpServletResponse.SC_NOT_FOUND;
- return this;
- }
- @Override
- public Reply<E> unauthorized() {
- status = HttpServletResponse.SC_UNAUTHORIZED;
- return this;
- }
- @Override
- public Reply<E> as(Key<? extends Transport> transport) {
- Preconditions.checkArgument(null != transport, "Transport class cannot be null!");
- this.transport = transport;
- return this;
- }
- @Override
- public Reply<E> as(Class<? extends Transport> transport) {
- Preconditions.checkArgument(null != transport, "Transport class cannot be null!");
- this.transport = Key.get(transport);
- return this;
- }
- @Override
- public Reply<E> redirect(String url) {
- Strings.nonEmpty(url, "Redirect URL must be non empty!");
- this.redirectUri = url;
- status = HttpServletResponse.SC_MOVED_TEMPORARILY;
- return this;
- }
- @Override
- public Reply<E> forbidden() {
- status = HttpServletResponse.SC_FORBIDDEN;
- return this;
- }
- @Override
- public Reply<E> noContent() {
- status = HttpServletResponse.SC_NO_CONTENT;
- return this;
- }
- @Override
- public Reply<E> error() {
- status = HttpServletResponse.SC_INTERNAL_SERVER_ERROR;
- return this;
- }
- @Override
- public Reply<E> badRequest() {
- status = HttpServletResponse.SC_BAD_REQUEST;
- return this;
- }
- @Override
- public Reply<E> status(int code) {
- status = code;
- return this;
- }
- @Override
- public Reply<E> ok() {
- status = HttpServletResponse.SC_OK;
- return this;
- }
- @Override
- public Reply<E> template(Class<?> templateKey) {
- this.templateKey = templateKey;
- return this;
- }
- @Override @SuppressWarnings("unchecked")
- void populate(Injector injector, HttpServletResponse response) throws IOException {
- // If we should not bother with the chain
- if (Reply.NO_REPLY == this) {
- injector.getInstance(HttpServletRequest.class).setAttribute(Reply.NO_REPLY_ATTR, Boolean.TRUE);
- return;
- }
- // This is where we take all the builder values and encode them in the response.
- Transport transport = injector.getInstance(this.transport);
- // Set any headers (we do this first, so we can override any cheekily set headers).
- if (!headers.isEmpty()) {
- for (Map.Entry<String, String> header : headers.entrySet()) {
- response.setHeader(header.getKey(), header.getValue());
- }
- }
- // If the content type was already set, do nothing.
- if (response.getContentType() == null) {
- // By default we use the content type of the transport.
- if (null == contentType) {
- response.setContentType(transport.contentType());
- } else {
- response.setContentType(contentType);
- }
- }
- // Send redirect
- if (null != redirectUri) {
- response.sendRedirect(redirectUri);
- response.setStatus(status); // HACK to override whatever status the redirect sets.
- return;
- }
- // Write out data.
- response.setStatus(status);
- if (null != templateKey) {
- response.getWriter().write(injector.getInstance(Templates.class).render(templateKey, entity));
- } else if (null != entity) {
- if (entity instanceof InputStream) {
- // Stream the response rather than marshalling it through a transport.
- InputStream inputStream = (InputStream) entity;
- try {
- ByteStreams.copy(inputStream, response.getOutputStream());
- } finally {
- inputStream.close();
- }
- } else {
- // TODO(dhanji): This feels wrong to me. We need a better way to obtain the entity type.
- transport.out(response.getOutputStream(), (Class<E>) entity.getClass(), entity);
- }
- }
- }
-
- @Override
- public boolean equals(Object other) {
- if(!(other instanceof ReplyMaker<?>))
- return false;
-
- @SuppressWarnings("unchecked")
- ReplyMaker<E> o = (ReplyMaker<E>)other;
- if(this.status != o.status)
- return false;
-
- if((this.contentType != o.contentType)
- && (this.contentType != null && !this.contentType.equals(o.contentType))
- && (this.contentType == null && o.contentType != null))
- return false;
-
- if((this.redirectUri != o.redirectUri)
- && (this.redirectUri != null && !this.redirectUri.equals(o.redirectUri))
- && (this.redirectUri == null && o.redirectUri != null))
- return false;
-
- if(!this.headers.equals(o.headers))
- return false;
-
- if(!this.transport.equals(o.transport))
- return false;
-
- if(this.templateKey != o.templateKey)
- return false;
- if((this.entity != o.entity)
- && (this.entity != null && !this.entity.equals(o.entity))
- && (this.entity == null && o.entity != null))
- return false;
-
- // All tests passed, the objects must be equal
- return true;
- }
- }