package glaze.util; import glaze.spi.Registry; import java.io.BufferedInputStream; import java.io.BufferedOutputStream; import java.io.IOException; import java.io.OutputStream; import java.io.StringWriter; import org.apache.http.HttpEntity; import org.apache.http.entity.BasicHttpEntity; import org.apache.http.entity.ContentType; import org.apache.http.entity.StringEntity; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.fasterxml.jackson.databind.ObjectMapper; import com.google.common.base.Optional; public class EntityMapper { private enum Maps { UrlEncodedMap { @Override boolean accept(String ns, Object bean, ContentType type) { return ContentType.APPLICATION_FORM_URLENCODED.getMimeType().equals(type.getMimeType()); } @Override HttpEntity map(String ns, Object bean, ContentType type) { return FormHelper.asUrlEncodedFormEntity(bean); } }, MultipartMap { @Override boolean accept(String ns, Object bean, ContentType type) { return ContentType.MULTIPART_FORM_DATA.getMimeType().equals(type.getMimeType()); } @Override HttpEntity map(String ns, Object bean, ContentType type) { return FormHelper.asMultipartEntity(bean); } }, ObjectMapperMap { @Override boolean accept(String ns, Object bean, ContentType type) { ObjectMapper mapper = Registry.lookupMapper(ns, type); return mapper != null && mapper.canSerialize(bean.getClass()); } @Override HttpEntity map(String ns, Object bean, ContentType type) { ObjectMapper mapper = Registry.lookupMapper(ns, type); CircularByteBuffer cbb = new CircularByteBuffer(CircularByteBuffer.INFINITE_SIZE); OutputStream out = cbb.getOutputStream(); try { mapper.writeValue(new BufferedOutputStream(cbb.getOutputStream()), bean); BasicHttpEntity basicEntity = new BasicHttpEntity(); basicEntity.setContent(new BufferedInputStream(cbb.getInputStream())); basicEntity.setContentType(type.toString()); return basicEntity; } catch (IOException e) { LOGGER.error(String.format("Error mapping '%s', returning a dummy StringEntity.", bean.getClass()), e); return new StringEntity(bean.toString(), type); } finally { try { out.close(); } catch (IOException e) { LOGGER.error(e.getMessage(), e); } } } @Override HttpEntity repeatableMap(String ns, Object bean, ContentType type) { ObjectMapper mapper = Registry.lookupMapper(ns, type); StringWriter writer = new StringWriter(); try { mapper.writeValue(writer, bean); } catch (IOException e) { LOGGER.error(e.getMessage(), e); } finally { try { writer.close(); } catch (IOException e) { LOGGER.error(e.getMessage(), e); } } return new StringEntity(writer.toString(), type); } }, // Always keep fall-back last Fallback { @Override boolean accept(String ns, Object bean, ContentType type) { return true; } @Override HttpEntity map(String ns, Object bean, ContentType type) { return new StringEntity(bean.toString(), type); } }; abstract boolean accept(String ns, Object bean, ContentType type); abstract HttpEntity map(String ns, Object bean, ContentType type); HttpEntity repeatableMap(String ns, Object bean, ContentType type) { return map(null, bean, type); } } private static final Logger LOGGER = LoggerFactory.getLogger(EntityMapper.class); public static HttpEntity map(Object bean, ContentType type) { return map(Registry.NS_DEFAULT, bean, type, false); } public static HttpEntity map(String namespace, Object bean, ContentType type, boolean repeatable) { String ns = Optional.fromNullable(namespace).or(Registry.NS_DEFAULT); for (Maps m : Maps.values()) { if (m.accept(ns, bean, type)) { return repeatable ? m.repeatableMap(ns, bean, type) : m.map(ns, bean, type); } } return new StringEntity(bean.toString(), type); } }