All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.google.api.server.spi.response.ServletResponseResultWriter Maven / Gradle / Ivy

There is a newer version: 2.2.2
Show newest version
/*
 * Copyright 2016 Google Inc. All Rights Reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.google.api.server.spi.response;

import com.google.api.server.spi.ConfiguredObjectMapper;
import com.google.api.server.spi.Constant;
import com.google.api.server.spi.ServiceException;
import com.google.api.server.spi.SystemService;
import com.google.api.server.spi.config.model.ApiSerializationConfig;
import com.google.api.server.spi.types.DateAndTime;
import com.google.api.server.spi.types.SimpleDate;
import com.google.appengine.api.datastore.Blob;

import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.Version;
import com.fasterxml.jackson.databind.JsonSerializer;
import com.fasterxml.jackson.databind.ObjectWriter;
import com.fasterxml.jackson.databind.SerializerProvider;
import com.fasterxml.jackson.databind.module.SimpleModule;

import java.io.IOException;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.LinkedHashSet;
import java.util.Map;
import java.util.Set;

import javax.servlet.http.HttpServletResponse;

/**
 * Writes a result to a servlet response.
 */
public class ServletResponseResultWriter implements ResultWriter {

  private static final Set WRITER_MODULES;

  static {
    Set modules = new LinkedHashSet<>();
    modules.add(getWriteLongAsStringModule());
    modules.add(getWriteDateAsStringModule());
    modules.add(getWriteDateAndTimeAsStringModule());
    modules.add(getWriteSimpleDateAsStringModule());
    try {
      // Attempt to load the Blob class, which may not exist outside of App Engine Standard.
      ServletResponseResultWriter.class.getClassLoader()
          .loadClass("com.google.appengine.api.datastore.Blob");
      modules.add(getWriteBlobAsBase64Module());
    } catch (ClassNotFoundException e) {
      // Ignore this error, since we can function without the Blob deserializer.
    }
    WRITER_MODULES = Collections.unmodifiableSet(modules);
  }

  private final HttpServletResponse servletResponse;
  private final ObjectWriter objectWriter;

  public ServletResponseResultWriter(
      HttpServletResponse servletResponse, ApiSerializationConfig serializationConfig) {
    this(servletResponse, serializationConfig, false /* prettyPrint */);
  }

  public ServletResponseResultWriter(
      HttpServletResponse servletResponse, ApiSerializationConfig serializationConfig,
      boolean prettyPrint) {
    this.servletResponse = servletResponse;
    Set modules = new LinkedHashSet<>();
    modules.addAll(WRITER_MODULES);
    ObjectWriter objectWriter = ConfiguredObjectMapper.builder()
        .apiSerializationConfig(serializationConfig)
        .addRegisteredModules(modules)
        .build()
        .writer();

    if (prettyPrint) {
      objectWriter = objectWriter.with(new EndpointsPrettyPrinter());
    }
    this.objectWriter = objectWriter;
  }

  @Override
  public void write(Object response) throws IOException {
    if (response == null) {
      write(HttpServletResponse.SC_NO_CONTENT, null, null);
    } else {
      write(HttpServletResponse.SC_OK, null,
          writeValueAsString(ResponseUtil.wrapCollection(response)));
    }
  }

  @Override
  public void writeError(ServiceException e) throws IOException {
    Map errors = new HashMap<>();
    errors.put(Constant.ERROR_MESSAGE, e.getMessage());
    write(e.getStatusCode(), e.getHeaders(),
        writeValueAsString(errors));
  }

  protected void write(int status, Map headers, String content) throws IOException {
    // write response status code
    servletResponse.setStatus(status);

    // write response headers
    if (headers != null) {
      for (Map.Entry entry : headers.entrySet()) {
        servletResponse.addHeader(entry.getKey(), entry.getValue());
      }
    }

    // write response body
    if (content != null) {
      servletResponse.setContentType(SystemService.MIME_JSON);
      servletResponse.setContentLength(content.getBytes("UTF-8").length);
      servletResponse.getWriter().write(content);
    }
  }

  private static SimpleModule getWriteLongAsStringModule() {
    JsonSerializer longSerializer = new JsonSerializer() {
      @Override
      public void serialize(Long value, JsonGenerator jgen, SerializerProvider provider)
          throws IOException {
        jgen.writeString(value.toString());
      }
    };
    SimpleModule writeLongAsStringModule = new SimpleModule("writeLongAsStringModule",
        new Version(1, 0, 0, null, null, null));
    writeLongAsStringModule.addSerializer(Long.TYPE, longSerializer);  // long (primitive)
    writeLongAsStringModule.addSerializer(Long.class, longSerializer); // Long (class)
    return writeLongAsStringModule;
  }

  private static SimpleModule getWriteDateAndTimeAsStringModule() {
    JsonSerializer dateAndTimeSerializer = new JsonSerializer() {
      @Override
      public void serialize(DateAndTime value, JsonGenerator jgen, SerializerProvider provider)
          throws IOException {
        jgen.writeString(value.toRfc3339String());
      }
    };
    SimpleModule writeDateAsStringModule = new SimpleModule("writeDateAsStringModule",
        new Version(1, 0, 0, null, null, null));
    writeDateAsStringModule.addSerializer(DateAndTime.class, dateAndTimeSerializer);
    return writeDateAsStringModule;
  }

  private static SimpleModule getWriteSimpleDateAsStringModule() {
    JsonSerializer simpleDateSerializer = new JsonSerializer() {
      @Override
      public void serialize(SimpleDate value, JsonGenerator jgen, SerializerProvider provider)
          throws IOException {
        jgen.writeString(
            String.format("%04d-%02d-%02d", value.getYear(), value.getMonth(), value.getDay()));
      }
    };
    SimpleModule writeSimpleDateAsModule = new SimpleModule("writeSimpleDateAsModule",
        new Version(1, 0, 0, null, null, null));
    writeSimpleDateAsModule.addSerializer(SimpleDate.class, simpleDateSerializer);
    return writeSimpleDateAsModule;
  }


  private static SimpleModule getWriteDateAsStringModule() {
    JsonSerializer dateSerializer = new JsonSerializer() {
      @Override
      public void serialize(Date value, JsonGenerator jgen, SerializerProvider provider)
          throws IOException {
        jgen.writeString(new com.google.api.client.util.DateTime(value).toStringRfc3339());
      }
    };
    SimpleModule writeDateAsStringModule = new SimpleModule("writeDateAsStringModule",
        new Version(1, 0, 0, null, null, null));
    writeDateAsStringModule.addSerializer(Date.class, dateSerializer);
    return writeDateAsStringModule;
  }

  private static SimpleModule getWriteBlobAsBase64Module() {
    JsonSerializer dateSerializer = new JsonSerializer() {
      @Override
      public void serialize(Blob value, JsonGenerator jgen, SerializerProvider provider)
          throws IOException {
        byte[] bytes = value.getBytes();
        jgen.writeBinary(bytes, 0, bytes.length);
      }
    };
    SimpleModule writeBlobAsBase64Module = new SimpleModule("writeBlobAsBase64Module",
        new Version(1, 0, 0, null, null, null));
    writeBlobAsBase64Module.addSerializer(Blob.class, dateSerializer);
    return writeBlobAsBase64Module;
  }

  // Writes a value as a JSON string and translates Jackson exceptions into IOException.
  protected String writeValueAsString(Object value)
      throws IOException {
    try {
      return objectWriter.writeValueAsString(value);
    } catch (JsonProcessingException e) {
      throw new IOException(e);
    }
  }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy