| OLD | NEW |
| (Empty) |
| 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. | |
| 2 // Use of this source code is governed by a BSD-style license that can be | |
| 3 // found in the LICENSE file. | |
| 4 | |
| 5 package org.chromium.sdk.internal.wip; | |
| 6 | |
| 7 import org.chromium.sdk.RelayOk; | |
| 8 import org.chromium.sdk.SyncCallback; | |
| 9 import org.chromium.sdk.internal.wip.protocol.input.WipCommandResponse; | |
| 10 import org.chromium.sdk.internal.wip.protocol.output.WipParams; | |
| 11 import org.chromium.sdk.internal.wip.protocol.output.WipParamsWithResponse; | |
| 12 import org.chromium.sdk.util.GenericCallback; | |
| 13 import org.chromium.sdk.util.RelaySyncCallback; | |
| 14 | |
| 15 /** | |
| 16 * A utility class that helps running a chain of asynchronous commands in a safe
manner. | |
| 17 * 'Safe' here means that the client will get {@link SyncCallback} called in the
end | |
| 18 * in any scenario. | |
| 19 * <p> | |
| 20 * The class helps reformat control sequence: instead of being callback-driven,
the program | |
| 21 * becomes step-driven. Each step defines a request being sent, the way a respon
se is processed | |
| 22 * and a link to the next step. | |
| 23 * <p> | |
| 24 * The class is bound to {@link WipCommandProcessor}. | |
| 25 */ | |
| 26 public class WipRelayRunner { | |
| 27 | |
| 28 /** | |
| 29 * The main abstraction of {@link WipRelayRunner}. A particular relay consists
is a chain | |
| 30 * of steps. Each step returns a next step except for the 'final' step | |
| 31 * (see {@link WipRelayRunner#createFinalStep(Object)}). | |
| 32 * <p>This type is essentially an algebraic data type. | |
| 33 * | |
| 34 * @param <RES> a type that the entire relay should return | |
| 35 */ | |
| 36 interface Step<RES> { | |
| 37 <R> R accept(Visitor<R, RES> visitor); | |
| 38 | |
| 39 interface Visitor<R, RES> { | |
| 40 R visitFinal(RES finalResult); | |
| 41 R visitSend(SendStepSimple<RES> sendStep); | |
| 42 <DATA> R visitSend(SendStepWithResponse<DATA, RES> sendStep); | |
| 43 } | |
| 44 } | |
| 45 | |
| 46 /** | |
| 47 * Creates a final step that simply holds a result. | |
| 48 */ | |
| 49 public static <RES> Step<RES> createFinalStep(final RES finalResult) { | |
| 50 return new Step<RES>() { | |
| 51 @Override | |
| 52 public <R> R accept(Visitor<R, RES> visitor) { | |
| 53 return visitor.visitFinal(finalResult); | |
| 54 } | |
| 55 }; | |
| 56 } | |
| 57 | |
| 58 /** | |
| 59 * A base class for 'send' step that sends a request and processes its respons
e. | |
| 60 * @param <RES> a type that the entire relay should return | |
| 61 */ | |
| 62 public static abstract class SendStepSimple<RES> implements Step<RES> { | |
| 63 public abstract WipParams getParams(); | |
| 64 | |
| 65 /** | |
| 66 * Handles normal response and returns a next step (or throws {@link Process
Exception}). | |
| 67 * The response itself contains no data, so there's no such parameter. | |
| 68 */ | |
| 69 public abstract Step<RES> processResponse() throws ProcessException; | |
| 70 | |
| 71 /** | |
| 72 * Optionally wraps the cause with a more high-level exception. Must return
cause by default. | |
| 73 * @return not null | |
| 74 */ | |
| 75 public abstract Exception processFailure(Exception cause); | |
| 76 | |
| 77 @Override public final <R> R accept(Visitor<R, RES> visitor) { | |
| 78 return visitor.visitSend(this); | |
| 79 } | |
| 80 } | |
| 81 | |
| 82 public static abstract class SendStepWithResponse<DATA, RES> implements Step<R
ES> { | |
| 83 public abstract WipParamsWithResponse<DATA> getParams(); | |
| 84 | |
| 85 /** | |
| 86 * Handles normal response and returns a next step (or throws {@link Process
Exception}). | |
| 87 */ | |
| 88 public abstract Step<RES> processResponse(DATA response) throws ProcessExcep
tion; | |
| 89 | |
| 90 /** | |
| 91 * Optionally wraps the cause with a more high-level exception. Must return
cause by default. | |
| 92 * @return not null | |
| 93 */ | |
| 94 public abstract Exception processFailure(Exception cause); | |
| 95 | |
| 96 @Override public final <R> R accept(Visitor<R, RES> visitor) { | |
| 97 return visitor.visitSend(this); | |
| 98 } | |
| 99 } | |
| 100 | |
| 101 /** | |
| 102 * An exception that step can throw if response cannot be processed normally.
It aborts the relay | |
| 103 * and gets passed to user callback. | |
| 104 */ | |
| 105 public static class ProcessException extends Exception { | |
| 106 public ProcessException() { | |
| 107 } | |
| 108 public ProcessException(String message, Throwable cause) { | |
| 109 super(message, cause); | |
| 110 } | |
| 111 public ProcessException(String message) { | |
| 112 super(message); | |
| 113 } | |
| 114 public ProcessException(Throwable cause) { | |
| 115 super(cause); | |
| 116 } | |
| 117 } | |
| 118 | |
| 119 /** | |
| 120 * Runs a relay defined by a chain of steps. | |
| 121 * @param <RES> return type of the entire relay | |
| 122 * @param firstStep a first step that defines the entire relay | |
| 123 * @param callback | |
| 124 * @param relaySyncCallback a {@link SyncCallback} wrapped as {@link RelaySync
Callback} | |
| 125 */ | |
| 126 public static <RES> RelayOk run(final WipCommandProcessor commandProcessor, St
ep<RES> firstStep, | |
| 127 final GenericCallback<RES> callback, final RelaySyncCallback relaySyncCall
back) { | |
| 128 | |
| 129 return firstStep.accept(new Step.Visitor<RelayOk, RES>() { | |
| 130 @Override | |
| 131 public RelayOk visitFinal(RES finalResult) { | |
| 132 if (callback != null) { | |
| 133 callback.success(finalResult); | |
| 134 } | |
| 135 return relaySyncCallback.finish(); | |
| 136 } | |
| 137 | |
| 138 @Override | |
| 139 public RelayOk visitSend(final SendStepSimple<RES> sendStep) { | |
| 140 final RelaySyncCallback.Guard guard = relaySyncCallback.newGuard(); | |
| 141 | |
| 142 WipCommandCallback sendCallback = new WipCommandCallback() { | |
| 143 @Override | |
| 144 public void messageReceived(WipCommandResponse response) { | |
| 145 Step<RES> processResult; | |
| 146 try { | |
| 147 processResult = sendStep.processResponse(); | |
| 148 } catch (ProcessException e) { | |
| 149 if (callback != null) { | |
| 150 callback.failure(e); | |
| 151 } | |
| 152 // Todo: consider throwing e. | |
| 153 return; | |
| 154 } | |
| 155 RelayOk relayOk = run(commandProcessor, processResult, callback, gua
rd.getRelay()); | |
| 156 guard.discharge(relayOk); | |
| 157 } | |
| 158 @Override | |
| 159 public void failure(String message) { | |
| 160 if (callback != null) { | |
| 161 callback.failure(sendStep.processFailure(new Exception(message))); | |
| 162 } | |
| 163 } | |
| 164 }; | |
| 165 | |
| 166 return commandProcessor.send(sendStep.getParams(), sendCallback, guard.a
sSyncCallback()); | |
| 167 } | |
| 168 | |
| 169 @Override | |
| 170 public <RESPONSE> RelayOk visitSend(final SendStepWithResponse<RESPONSE, R
ES> sendStep) { | |
| 171 final RelaySyncCallback.Guard guard = relaySyncCallback.newGuard(); | |
| 172 | |
| 173 GenericCallback<RESPONSE> sendCallback = new GenericCallback<RESPONSE>()
{ | |
| 174 @Override | |
| 175 public void success(RESPONSE response) { | |
| 176 Step<RES> processResult; | |
| 177 try { | |
| 178 processResult = sendStep.processResponse(response); | |
| 179 } catch (ProcessException e) { | |
| 180 if (callback != null) { | |
| 181 callback.failure(e); | |
| 182 } | |
| 183 // Todo: consider throwing e. | |
| 184 return; | |
| 185 } | |
| 186 RelayOk relayOk = run(commandProcessor, processResult, callback, gua
rd.getRelay()); | |
| 187 guard.discharge(relayOk); | |
| 188 } | |
| 189 | |
| 190 @Override | |
| 191 public void failure(Exception exception) { | |
| 192 if (callback != null) { | |
| 193 callback.failure(sendStep.processFailure(exception)); | |
| 194 } | |
| 195 } | |
| 196 }; | |
| 197 | |
| 198 return commandProcessor.send(sendStep.getParams(), sendCallback, guard.a
sSyncCallback()); | |
| 199 } | |
| 200 }); | |
| 201 } | |
| 202 } | |
| OLD | NEW |