Java tutorial
/** * This file is part of pwt. * * pwt is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser * General Public License as published by the Free Software Foundation, either version 3 of the * License, or (at your option) any later version. * * pwt is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser * General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License along with pwt. If not, * see <http://www.gnu.org/licenses/>. */ package fr.putnami.pwt.core.service.client; import com.google.common.collect.Lists; import com.google.common.collect.Sets; import com.google.gwt.core.client.GWT; import com.google.gwt.event.shared.GwtEvent; import com.google.gwt.http.client.RequestBuilder; import com.google.gwt.http.client.RequestCallback; import com.google.gwt.http.client.RequestException; import com.google.gwt.user.client.rpc.AsyncCallback; import com.google.gwt.user.client.rpc.RpcRequestBuilder; import com.google.gwt.user.client.rpc.SerializationException; import com.google.gwt.user.client.rpc.SerializationStreamFactory; import com.google.gwt.user.client.rpc.SerializationStreamWriter; import com.google.gwt.user.client.rpc.StatusCodeException; import com.google.gwt.user.client.rpc.impl.RequestCallbackAdapter; import com.google.gwt.user.client.rpc.impl.RequestCallbackAdapter.ResponseReader; import com.google.gwt.user.client.rpc.impl.RpcStatsContext; import com.google.gwt.user.client.rpc.impl.Serializer; import com.google.web.bindery.event.shared.HandlerRegistration; import java.util.Collection; import java.util.Collections; import java.util.List; import java.util.Stack; import fr.putnami.pwt.core.error.client.ErrorManager; import fr.putnami.pwt.core.event.client.EventBus; import fr.putnami.pwt.core.service.client.error.ClientErrorHandler; import fr.putnami.pwt.core.service.client.error.DefaultCommandExceptionErrorHandler; import fr.putnami.pwt.core.service.client.error.ServerErrorHandler; import fr.putnami.pwt.core.service.client.event.CommandRequestEvent; import fr.putnami.pwt.core.service.client.event.CommandResponseEvent; import fr.putnami.pwt.core.service.shared.domain.CommandDefinition; import fr.putnami.pwt.core.service.shared.domain.CommandRequest; import fr.putnami.pwt.core.service.shared.domain.CommandResponse; import fr.putnami.pwt.core.service.shared.exception.CommandException; import fr.putnami.pwt.core.service.shared.service.CommandService; public final class DefaultCommandController extends CommandController { private class ServiceCallback extends CallbackAdapter<List<CommandResponse>> { private final List<Request> requests; private AsyncCallback<List<CommandResponse>> callback; ServiceCallback(List<Request> requests, AsyncCallback<List<CommandResponse>> callback) { this.requests = requests; this.callback = callback; } @Override public void onSuccess(List<CommandResponse> responses) { for (CommandResponse response : responses) { for (Request request : this.requests) { if (request.requestId == response.getRequestId()) { if (!request.param.isQuiet()) { DefaultCommandController.this.fireEvent( new CommandResponseEvent(request.requestId, request.command, response)); } if (response.getThrown() == null) { for (AsyncCallback requestCallback : request.param.getCallbacks()) { if (response.getResult().size() == 1) { requestCallback.onSuccess(response.getResult().get(0)); } else { requestCallback.onSuccess(null); } } } else { boolean caught = false; for (AsyncCallback requestCallback : request.param.getCallbacks()) { try { requestCallback.onFailure(response.getThrown()); caught = true; } catch (RuntimeException e) { // Exception not handled. continue; } } if (!caught) { GWT.reportUncaughtException(response.getThrown()); } } } } } if (this.callback != null) { this.callback.onSuccess(responses); } } @Override public void onFailure(Throwable caught) { if (caught instanceof StatusCodeException) { GWT.reportUncaughtException(caught); } else { for (Request request : this.requests) { if (request.param.getCallbacks().isEmpty()) { GWT.reportUncaughtException(caught); } for (AsyncCallback requestCallback : request.param.getCallbacks()) { requestCallback.onFailure(caught); } } if (this.callback != null) { this.callback.onFailure(caught); } } } } private static class Request { private long requestId; private CommandRequest command; private CommandParam param; } private static final String RPC_CONTENT_TYPE = "text/x-gwt-rpc; charset=utf-8"; private static final String REMOTE_SERVICE_INTERFACE_NAME = CommandService.class.getName(); private static final String METHOD_NAME = "executeCommands"; private static DefaultCommandController instance; private final RpcRequestBuilder rpcRequestBuilder = new RpcRequestBuilder(); private final String moduleBaseURL; private final String remoteServiceURL; private long requestIdSequence = 0; private boolean suspended = false; private Stack<Request> stack = new Stack<Request>(); private DefaultCommandController() { this.moduleBaseURL = GWT.getHostPageBaseURL(); this.remoteServiceURL = this.moduleBaseURL + "commandService"; ErrorManager.get().registerErrorHandlers(new ClientErrorHandler(), new ServerErrorHandler(), new DefaultCommandExceptionErrorHandler()); } @Override public CommandRequest invokeCommand(CommandDefinition commandDefinition, CommandParam commandParam) { long requestId = ++this.requestIdSequence; CommandRequest command = new CommandRequest(); command.setRequestId(requestId); command.setCommandDefinition(commandDefinition); command.setArgs(commandParam.getParams()); Request request = new Request(); request.requestId = requestId; request.param = commandParam; request.command = command; if (this.suspended || request.param.isLazy()) { this.stack.push(request); } else { this.sendRequest(Lists.newArrayList(request), null); } return command; } @Override public int flush() { return this.flush(null); } @Override public int flush(AsyncCallback<List<CommandResponse>> callback) { try { int result = this.sendRequest(Lists.newArrayList(this.stack), callback); if (result == 0 && callback != null) { callback.onSuccess(Collections.<CommandResponse>emptyList()); } return result; } finally { this.stack.clear(); } } @Override public int countPendingRequest() { return this.stack.size(); } @Override public boolean isSuspended() { return this.suspended; } @Override public void setSuspended(boolean suspended) { this.suspended = suspended; if (!suspended) { this.flush(); } } private int sendRequest(List<Request> requests, AsyncCallback<List<CommandResponse>> callback) { if (requests == null || requests.isEmpty()) { return 0; } try { Collection<Serializer> serializers = Sets.newHashSet(); List<CommandRequest> commands = Lists.newArrayList(); for (Request request : requests) { serializers.add(request.param.getSerializer()); commands.add(request.command); if (!request.param.isQuiet()) { this.fireEvent(new CommandRequestEvent(request.requestId, request.command)); } } ServiceCallback serviceCallback = new ServiceCallback(requests, callback); CommandServiceCompositeSerializer compositeSerializer = new CommandServiceCompositeSerializer( serializers); SerializationStreamFactory streamFactory = new CommandSerializationStreamFactory(compositeSerializer, this.moduleBaseURL); SerializationStreamWriter streamWriter = streamFactory.createStreamWriter(); streamWriter.writeString(DefaultCommandController.REMOTE_SERVICE_INTERFACE_NAME); streamWriter.writeString(DefaultCommandController.METHOD_NAME); streamWriter.writeInt(1); streamWriter.writeString(List.class.getName()); streamWriter.writeObject(commands); String payload = streamWriter.toString(); RpcStatsContext statsContext = new RpcStatsContext(); RequestCallback responseHandler = new RequestCallbackAdapter<List<CommandResponse>>(streamFactory, DefaultCommandController.METHOD_NAME, statsContext, serviceCallback, null, ResponseReader.OBJECT); this.rpcRequestBuilder.create(this.remoteServiceURL); this.rpcRequestBuilder.setCallback(responseHandler); this.rpcRequestBuilder.setContentType(DefaultCommandController.RPC_CONTENT_TYPE); this.rpcRequestBuilder.setRequestData(payload); this.rpcRequestBuilder.setRequestId(statsContext.getRequestId()); RequestBuilder rb = this.rpcRequestBuilder.finish(); CsrfController.get().securize(rb); rb.send(); return requests.size(); } catch (SerializationException e) { throw new CommandException(e.getMessage()); } catch (RequestException e) { throw new CommandException(e.getMessage()); } } @Override public void fireEvent(GwtEvent<?> event) { EventBus.get().fireEventFromSource(event, this); } @Override public HandlerRegistration addCommandRequestHandler(CommandRequestEvent.Handler handler) { return EventBus.get().addHandlerToSource(CommandRequestEvent.TYPE, this, handler); } @Override public HandlerRegistration addCommandResponseHandler(CommandResponseEvent.Handler handler) { return EventBus.get().addHandlerToSource(CommandResponseEvent.TYPE, this, handler); } public static DefaultCommandController get() { if (instance == null) { instance = new DefaultCommandController(); } return instance; } }