/*
* Copyright 2014 Grow Bit
*
* 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 org.turbogwt.net.http.client;
import com.google.gwt.core.client.GWT;
import com.google.gwt.http.client.Header;
import com.google.gwt.http.client.Request;
import com.google.gwt.http.client.RequestBuilder;
import com.google.gwt.http.client.RequestCallback;
import com.google.gwt.http.client.RequestCallbackWithProgress;
import com.google.gwt.http.client.RequestException;
import com.google.gwt.http.client.RequestProgress;
import com.google.gwt.http.client.Response;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import org.turbogwt.net.http.client.header.AcceptHeader;
import org.turbogwt.net.http.client.header.ContentTypeHeader;
import org.turbogwt.net.http.client.header.SimpleHeader;
import org.turbogwt.net.http.client.serialization.HttpSerializationContext;
import org.turbogwt.net.serialization.client.ContainerFactoryManager;
import org.turbogwt.net.serialization.client.SerdesManager;
import org.turbogwt.net.serialization.client.Serializer;
/**
* Default implementation for {@link Request}.
*/
public class RequestImpl implements RequestDispatcher {
private final Server server = GWT.create(Server.class);
private final SerdesManager serdesManager;
private final ContainerFactoryManager containerFactoryManager;
private final String uri;
private final FilterManager filterManager;
private Headers headers;
private String user;
private String password;
private int timeout;
private String contentType;
private AcceptHeader accept;
private Object payload;
public RequestImpl(String uri, SerdesManager serdesManager, ContainerFactoryManager containerFactoryManager,
FilterManager filterManager) {
this.serdesManager = serdesManager;
this.containerFactoryManager = containerFactoryManager;
this.filterManager = filterManager;
// TODO: parse URI
this.uri = uri;
}
@Override
public RequestDispatcher contentType(String contentType) {
this.contentType = contentType;
return this;
}
@Override
public RequestDispatcher accept(String contentType) {
this.accept = new AcceptHeader(contentType);
return this;
}
@Override
public RequestDispatcher accept(AcceptHeader acceptHeader) {
this.accept = acceptHeader;
return this;
}
@Override
public RequestDispatcher header(String header, String value) {
ensureHeaders().add(new SimpleHeader(header, value));
return this;
}
@Override
public RequestDispatcher header(Header header) {
ensureHeaders().add(header);
return this;
}
@Override
public RequestDispatcher user(String user) {
this.user = user;
return this;
}
@Override
public RequestDispatcher password(String password) {
this.password = password;
return this;
}
@Override
public RequestDispatcher timeout(int timeoutMillis) {
timeout = timeoutMillis;
return this;
}
@Override
public RequestDispatcher payload(Object object) throws IllegalArgumentException {
payload = object;
return this;
}
@Override
public RequestPromise<Void> get() {
return send(RequestBuilder.GET, Void.class);
}
@Override
public <T> RequestPromise<T> get(Class<T> responseType) {
return send(RequestBuilder.GET, responseType);
}
@Override
public <T, C extends Collection> RequestPromise<Collection<T>> get(Class<T> responseType, Class<C> containerType) {
return send(RequestBuilder.GET, responseType, containerType);
}
@Override
public RequestPromise<Void> post() {
return send(RequestBuilder.POST, Void.class);
}
@Override
public <T> RequestPromise<T> post(Class<T> responseType) {
return send(RequestBuilder.POST, responseType);
}
@Override
public <T, C extends Collection> RequestPromise<Collection<T>> post(Class<T> responseType, Class<C> containerType) {
return send(RequestBuilder.POST, responseType, containerType);
}
@Override
public RequestPromise<Void> put() {
return send(RequestBuilder.PUT, Void.class);
}
@Override
public <T> RequestPromise<T> put(Class<T> responseType) {
return send(RequestBuilder.PUT, responseType);
}
@Override
public <T, C extends Collection> RequestPromise<Collection<T>> put(Class<T> responseType, Class<C> containerType) {
return send(RequestBuilder.PUT, responseType, containerType);
}
@Override
public RequestPromise<Void> delete() {
return send(RequestBuilder.DELETE, Void.class);
}
@Override
public <T> RequestPromise<T> delete(Class<T> responseType) {
return send(RequestBuilder.DELETE, responseType);
}
@Override
public <T, C extends Collection> RequestPromise<Collection<T>> delete(Class<T> responseType,
Class<C> containerType) {
return send(RequestBuilder.DELETE, responseType, containerType);
}
@Override
public RequestPromise<Void> head() {
return send(RequestBuilder.HEAD, Void.class);
}
@Override
public <T> RequestPromise<T> head(Class<T> responseType) {
return send(RequestBuilder.HEAD, responseType);
}
@Override
public <T, C extends Collection> RequestPromise<Collection<T>> head(Class<T> responseType, Class<C> containerType) {
return send(RequestBuilder.HEAD, responseType, containerType);
}
private <T> RequestPromise<T> send(RequestBuilder.Method method, Class<T> responseType) {
final DeferredSingleResult<T> deferred = new DeferredSingleResult<T>(responseType, serdesManager,
containerFactoryManager);
RequestCallback callback = createRequestCallback(deferred);
dispatch(method, callback);
return deferred;
}
private <T, C extends Collection> RequestPromise<Collection<T>> send(RequestBuilder.Method method,
Class<T> responseType,
Class<C> containerType) {
final DeferredCollectionResult<T> deferred = new DeferredCollectionResult<T>(responseType, containerType,
serdesManager, containerFactoryManager);
RequestCallback callback = createRequestCallback(deferred);
dispatch(method, callback);
return deferred;
}
private <D> RequestCallback createRequestCallback(final DeferredRequest<D> deferred) {
return new RequestCallbackWithProgress() {
@Override
public void onResponseReceived(Request request, Response response) {
// Execute filters on this response
final List<ResponseFilter> filters = filterManager.getResponseFilters();
for (ResponseFilter filter : filters) {
filter.filter(response);
}
if (response.getStatusCode() / 100 == 2) {
deferred.resolve(response);
} else {
deferred.reject(response);
}
}
@Override
public void onProgress(RequestProgress requestProgress) {
deferred.notify(new RequestProgressImpl(requestProgress));
}
@Override
public void onError(Request request, Throwable exception) {
deferred.reject(exception);
}
};
}
private void dispatch(RequestBuilder.Method method, RequestCallback callback) {
ensureHeaders();
// Execute filters on this request
final List<RequestFilter> filters = filterManager.getRequestFilters();
for (RequestFilter filter : filters) {
filter.filter(this);
}
String body = serializePayload();
ServerConnection connection = server.getConnection();
try {
connection.sendRequest(timeout, user, password, headers, method, uri, body, callback);
} catch (final RequestException e) {
throw new RequestDispatchException("It was not possible to dispatch the request.", e);
}
}
private String serializePayload() {
String body = null;
if (payload != null) {
if (payload instanceof Collection) {
Collection c = (Collection) payload;
final Iterator iterator = c.iterator();
Object item = null;
while (iterator.hasNext() && item == null) {
item = iterator.next();
}
if (item == null) {
/* TODO: Create some EmptyCollectionSerializer Manager
for serialization of empty collections by content-type */
body = "[]";
} else {
Serializer<?> serializer = serdesManager.getSerializer(item.getClass(), contentType);
body = serializer.serializeFromCollection(c, new HttpSerializationContext(ensureHeaders()));
}
} else {
@SuppressWarnings("unchecked")
Serializer<Object> serializer = (Serializer<Object>) serdesManager.getSerializer(payload.getClass(),
contentType);
body = serializer.serialize(payload, new HttpSerializationContext(ensureHeaders()));
}
}
return body;
}
private Headers ensureHeaders() {
if (headers == null) {
headers = new Headers();
headers.add(new ContentTypeHeader(contentType));
headers.add(accept);
}
return headers;
}
}