/* * Copyright 2015 ArcBees Inc. * * 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.gwtplatform.dispatch.rest.client.core; import java.util.List; import java.util.Set; import javax.inject.Inject; import javax.inject.Provider; import javax.ws.rs.core.HttpHeaders; import javax.ws.rs.core.MediaType; import com.google.gwt.http.client.RequestBuilder; import com.gwtplatform.dispatch.rest.client.serialization.Serialization; import com.gwtplatform.dispatch.rest.client.serialization.SerializationException; import com.gwtplatform.dispatch.rest.client.serialization.SerializedValue; import com.gwtplatform.dispatch.rest.shared.ContentType; import com.gwtplatform.dispatch.rest.shared.HttpParameter.Type; import com.gwtplatform.dispatch.rest.shared.RestAction; import com.gwtplatform.dispatch.shared.ActionException; public class DefaultBodyFactory implements BodyFactory { private final Provider<Set<Serialization>> serializationsProvider; private final UriFactory uriFactory; private Set<Serialization> serializations; @Inject DefaultBodyFactory( Provider<Set<Serialization>> serializationsProvider, UriFactory uriFactory) { this.serializationsProvider = serializationsProvider; this.uriFactory = uriFactory; } @Override public void buildBody(RequestBuilder requestBuilder, RestAction<?> action) throws ActionException { if (action.hasFormParams()) { assignBodyFromForm(requestBuilder, action); } else { assignBodyFromSerialization(requestBuilder, action); } } /** * Find a serializer capable of handling <code>bodyClass</code> and <code>contentTypes</code>. * * @param bodyClass the parameterized type to verify if it can be serialized. * @param contentTypes A list of content types a serializer is allowed to return. * * @return <code>true</code> if <code>bodyClass</code> can be serialized, otherwise <code>false</code>. */ protected Serialization findSerialization(String bodyClass, List<ContentType> contentTypes) { for (Serialization serialization : getSerializations()) { if (serialization.canSerialize(bodyClass, contentTypes)) { return serialization; } } return null; } /** * Serialize the given object using the given <code>serialization</code> instance. * * @param serialization the serialization object to be used. * @param object the object to serialize. * @param bodyClass The parameterized type of the object to serialize. * @param contentTypes A list of content types a serializer is allowed to return. * * @return The serialized string. */ protected SerializedValue serialize(Serialization serialization, Object object, String bodyClass, List<ContentType> contentTypes) throws ActionException { try { return serialization.serialize(bodyClass, contentTypes, object); } catch (SerializationException e) { throw new ActionException(e); } } private void assignBodyFromForm(RequestBuilder requestBuilder, RestAction<?> action) { String queryString = uriFactory.buildQueryString(action, Type.FORM); requestBuilder.setHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_FORM_URLENCODED); requestBuilder.setRequestData(queryString); } private void assignBodyFromSerialization(RequestBuilder requestBuilder, RestAction<?> action) throws ActionException { String data; if (action.hasBodyParam()) { SerializedValue serializedValue = getSerializedValue(action, action.getBodyParam()); ContentType contentType = serializedValue.getContentType(); data = serializedValue.getData(); requestBuilder.setHeader(HttpHeaders.CONTENT_TYPE, contentType.toString()); } else { // Fixes an issue for all IE versions (IE 11 is the latest at this time). If request data is not // explicitly set to 'null', the JS 'undefined' will be sent as the request body on IE. Other // browsers don't send undefined bodies. data = null; } requestBuilder.setRequestData(data); } private SerializedValue getSerializedValue(RestAction<?> action, Object object) throws ActionException { String bodyClass = action.getBodyClass(); if (bodyClass != null) { List<ContentType> contentTypes = action.getClientProducedContentTypes(); Serialization serialization = findSerialization(bodyClass, contentTypes); if (serialization != null) { return serialize(serialization, object, bodyClass, contentTypes); } } throw new ActionException("Unable to serialize request body. No serializer found."); } private Set<Serialization> getSerializations() { if (serializations == null) { serializations = serializationsProvider.get(); } return serializations; } }