|
5 | 5 |
|
6 | 6 | import com.azure.core.http.HttpPipeline; |
7 | 7 | import com.azure.core.http.rest.Response; |
| 8 | +import com.azure.core.management.implementation.polling.PollOperation; |
| 9 | +import com.azure.core.management.implementation.polling.PollingState; |
8 | 10 | import com.azure.core.management.implementation.polling.SyncPollOperation; |
9 | 11 | import com.azure.core.util.BinaryData; |
10 | 12 | import com.azure.core.util.Context; |
| 13 | +import com.azure.core.util.polling.PollResponse; |
| 14 | +import com.azure.core.util.polling.PollingContext; |
11 | 15 | import com.azure.core.util.polling.SyncPoller; |
12 | 16 | import com.azure.core.util.serializer.SerializerAdapter; |
13 | 17 |
|
14 | 18 | import java.lang.reflect.Type; |
15 | 19 | import java.time.Duration; |
| 20 | +import java.util.function.Function; |
16 | 21 | import java.util.function.Supplier; |
17 | 22 |
|
18 | 23 | /** |
@@ -62,10 +67,132 @@ public static <T, U> SyncPoller<PollResult<T>, U> create(SerializerAdapter seria |
62 | 67 | public static <T, U> SyncPoller<PollResult<T>, U> create(SerializerAdapter serializerAdapter, |
63 | 68 | HttpPipeline httpPipeline, Type pollResultType, Type finalResultType, Duration defaultPollDuration, |
64 | 69 | Supplier<Response<BinaryData>> lroInitialResponseSupplier, Context context) { |
65 | | - return SyncPoller.createPoller(defaultPollDuration, |
66 | | - SyncPollOperation.activationFunction(serializerAdapter, pollResultType, lroInitialResponseSupplier), |
| 70 | + |
| 71 | + // Create a holder for the PollingContext that we can access later |
| 72 | + @SuppressWarnings({ "unchecked", "rawtypes" }) |
| 73 | + final PollingContext<PollResult<T>>[] contextHolder = (PollingContext<PollResult<T>>[]) new PollingContext[1]; |
| 74 | + |
| 75 | + // Wrap the activation function to capture the context |
| 76 | + Function<PollingContext<PollResult<T>>, PollResponse<PollResult<T>>> wrappedActivation = pollingContext -> { |
| 77 | + contextHolder[0] = pollingContext; |
| 78 | + return SyncPollOperation |
| 79 | + .<T>activationFunction(serializerAdapter, pollResultType, lroInitialResponseSupplier) |
| 80 | + .apply(pollingContext); |
| 81 | + }; |
| 82 | + |
| 83 | + SyncPoller<PollResult<T>, U> innerPoller = SyncPoller.createPoller(defaultPollDuration, wrappedActivation, |
| 84 | + SyncPollOperation.pollFunction(serializerAdapter, httpPipeline, pollResultType, context), |
| 85 | + SyncPollOperation.cancelFunction(context), |
| 86 | + SyncPollOperation.fetchResultFunction(serializerAdapter, httpPipeline, finalResultType, context)); |
| 87 | + |
| 88 | + // Wrap in ArmLroSyncPoller to add continuation token support |
| 89 | + return new ArmLroSyncPoller<>(innerPoller, serializerAdapter, () -> contextHolder[0]); |
| 90 | + } |
| 91 | + |
| 92 | + /** |
| 93 | + * Resumes a SyncPoller for an Azure Resource Manager (ARM) long-running-operation (LRO) from a continuation token. |
| 94 | + * <p> |
| 95 | + * This method recreates a SyncPoller from a previously serialized continuation token, allowing the polling |
| 96 | + * operation to be resumed from its last known state. This is useful for scenarios where a process needs to |
| 97 | + * survive restarts or where polling needs to be transferred between different processes or instances. |
| 98 | + * <p> |
| 99 | + * The continuation token must have been obtained from a previous poller via |
| 100 | + * {@link SyncPoller#serializeContinuationToken()}. |
| 101 | + * <p> |
| 102 | + * <strong>Example: Resuming a server creation operation</strong> |
| 103 | + * <pre>{@code |
| 104 | + * // Original process - start operation and get token |
| 105 | + * SyncPoller<PollResult<ServerInner>, ServerInner> poller = |
| 106 | + * client.beginCreate(resourceGroup, serverName, parameters); |
| 107 | + * String token = poller.serializeContinuationToken(); |
| 108 | + * // Store token... |
| 109 | + * |
| 110 | + * // Later, in a different process - resume from token |
| 111 | + * SyncPoller<PollResult<ServerInner>, ServerInner> resumedPoller = |
| 112 | + * SyncPollerFactory.resumeFromToken( |
| 113 | + * token, |
| 114 | + * client.getSerializerAdapter(), |
| 115 | + * client.getHttpPipeline(), |
| 116 | + * new TypeReference<PollResult<ServerInner>>() {}.getJavaType(), |
| 117 | + * ServerInner.class, |
| 118 | + * Duration.ofSeconds(30), |
| 119 | + * Context.NONE); |
| 120 | + * |
| 121 | + * // Continue polling until completion |
| 122 | + * ServerInner result = resumedPoller.getFinalResult(); |
| 123 | + * }</pre> |
| 124 | + * |
| 125 | + * @param continuationToken The Base64-encoded continuation token string obtained from a previous poller. |
| 126 | + * @param serializerAdapter The serializer for any encoding and decoding. This should be the same type |
| 127 | + * as used by the original poller. |
| 128 | + * @param httpPipeline The HttpPipeline for making HTTP requests (e.g., poll requests). This should be |
| 129 | + * configured with the same authentication and policies as the original poller. |
| 130 | + * @param pollResultType The type of the poll result. If no result is expected, this should be Void.class. |
| 131 | + * @param finalResultType The type of the final result. If no result is expected, this should be Void.class. |
| 132 | + * @param defaultPollDuration The default poll interval to use if the service does not return a retry-after value. |
| 133 | + * @param context The context shared by all requests. |
| 134 | + * @param <T> The type of poll result. |
| 135 | + * @param <U> The type of final result. |
| 136 | + * @return A SyncPoller that resumes polling from the state captured in the continuation token. |
| 137 | + * @throws IllegalArgumentException if {@code continuationToken} or {@code serializerAdapter} is null or empty. |
| 138 | + * @throws RuntimeException if the token cannot be decoded or deserialized, which may occur if: |
| 139 | + * <ul> |
| 140 | + * <li>The token is malformed or corrupted</li> |
| 141 | + * <li>The token was created with a different SDK version</li> |
| 142 | + * <li>The token format has changed</li> |
| 143 | + * </ul> |
| 144 | + */ |
| 145 | + public static <T, U> SyncPoller<PollResult<T>, U> resumeFromToken(String continuationToken, |
| 146 | + SerializerAdapter serializerAdapter, HttpPipeline httpPipeline, Type pollResultType, Type finalResultType, |
| 147 | + Duration defaultPollDuration, Context context) { |
| 148 | + |
| 149 | + // Deserialize the continuation token to get the PollingState |
| 150 | + PollingState pollingState = PollingState.fromContinuationToken(continuationToken, serializerAdapter); |
| 151 | + |
| 152 | + // Create a holder for the PollingContext |
| 153 | + @SuppressWarnings({ "unchecked", "rawtypes" }) |
| 154 | + final PollingContext<PollResult<T>>[] contextHolder = (PollingContext<PollResult<T>>[]) new PollingContext[1]; |
| 155 | + |
| 156 | + // Create an activation function that returns the current state as the activation response |
| 157 | + Function<PollingContext<PollResult<T>>, PollResponse<PollResult<T>>> activationFunction = pollingContext -> { |
| 158 | + contextHolder[0] = pollingContext; |
| 159 | + pollingState.store(pollingContext); |
| 160 | + T result = PollOperation.deserialize(serializerAdapter, pollingState.getLastResponseBody(), pollResultType); |
| 161 | + return new PollResponse<>(pollingState.getOperationStatus(), new PollResult<>(result), |
| 162 | + pollingState.getPollDelay()); |
| 163 | + }; |
| 164 | + |
| 165 | + // Create the poller with the standard poll, cancel, and fetch result functions |
| 166 | + SyncPoller<PollResult<T>, U> innerPoller = SyncPoller.createPoller(defaultPollDuration, activationFunction, |
67 | 167 | SyncPollOperation.pollFunction(serializerAdapter, httpPipeline, pollResultType, context), |
68 | 168 | SyncPollOperation.cancelFunction(context), |
69 | 169 | SyncPollOperation.fetchResultFunction(serializerAdapter, httpPipeline, finalResultType, context)); |
| 170 | + |
| 171 | + // Wrap in ArmLroSyncPoller to add continuation token support |
| 172 | + return new ArmLroSyncPoller<>(innerPoller, serializerAdapter, () -> contextHolder[0]); |
| 173 | + } |
| 174 | + |
| 175 | + /** |
| 176 | + * Resumes a SyncPoller for an Azure Resource Manager (ARM) long-running-operation (LRO) from a continuation token. |
| 177 | + * <p> |
| 178 | + * This is a convenience overload that uses {@link Context#NONE} for the context parameter. |
| 179 | + * |
| 180 | + * @param continuationToken The Base64-encoded continuation token string obtained from a previous poller. |
| 181 | + * @param serializerAdapter The serializer for any encoding and decoding. |
| 182 | + * @param httpPipeline The HttpPipeline for making HTTP requests. |
| 183 | + * @param pollResultType The type of the poll result. |
| 184 | + * @param finalResultType The type of the final result. |
| 185 | + * @param defaultPollDuration The default poll interval to use. |
| 186 | + * @param <T> The type of poll result. |
| 187 | + * @param <U> The type of final result. |
| 188 | + * @return A SyncPoller that resumes polling from the state captured in the continuation token. |
| 189 | + * @throws IllegalArgumentException if {@code continuationToken} or {@code serializerAdapter} is null or empty. |
| 190 | + * @throws RuntimeException if the token cannot be decoded or deserialized. |
| 191 | + */ |
| 192 | + public static <T, U> SyncPoller<PollResult<T>, U> resumeFromToken(String continuationToken, |
| 193 | + SerializerAdapter serializerAdapter, HttpPipeline httpPipeline, Type pollResultType, Type finalResultType, |
| 194 | + Duration defaultPollDuration) { |
| 195 | + return resumeFromToken(continuationToken, serializerAdapter, httpPipeline, pollResultType, finalResultType, |
| 196 | + defaultPollDuration, Context.NONE); |
70 | 197 | } |
71 | 198 | } |
0 commit comments