// Copyright (c) 2011 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. package org.chromium.sdk.internal.wip; import java.util.Map; import org.chromium.sdk.CallbackSemaphore; import org.chromium.sdk.JsEvaluateContext; import org.chromium.sdk.JsValue; import org.chromium.sdk.JsVariable; import org.chromium.sdk.RelayOk; import org.chromium.sdk.RemoteValueMapping; import org.chromium.sdk.SyncCallback; import org.chromium.sdk.internal.JsEvaluateContextBase; import org.chromium.sdk.internal.wip.WipExpressionBuilder.ValueNameBuilder; import org.chromium.sdk.internal.wip.protocol.input.runtime.RemoteObjectValue; import org.chromium.sdk.internal.wip.protocol.output.WipParamsWithResponse; import org.chromium.sdk.util.GenericCallback; import org.chromium.sdk.util.MethodIsBlockingException; import org.chromium.sdk.wip.EvaluateToMappingExtension; /** * Basic implementation of the abstract {@link JsEvaluateContextBase}. Class leaves unimplemented * parts that deal with a particular context details (callframe or global) and particular protocol * message. * @param <DATA> type of protocol message response */ abstract class WipEvaluateContextBase<DATA> extends JsEvaluateContextBase { private final WipValueLoader valueLoader; WipEvaluateContextBase(WipValueLoader valueLoader) { this.valueLoader = valueLoader; } @Override public RelayOk evaluateAsync(final String expression, Map<String, String> additionalContext, final EvaluateCallback callback, SyncCallback syncCallback) { WipExpressionBuilder.ValueNameBuilder valueNameBuilder = WipExpressionBuilder.createRootName(expression, true); return evaluateAsync(expression, valueNameBuilder, additionalContext, valueLoader, callback, syncCallback); } RelayOk evaluateAsync(String expression, ValueNameBuilder valueNameBuidler, Map<String, String> additionalContext, final EvaluateCallback callback, SyncCallback syncCallback) { return evaluateAsync(expression, valueNameBuidler, additionalContext, valueLoader, callback, syncCallback); } private RelayOk evaluateAsync(String expression, final ValueNameBuilder valueNameBuidler, Map<String, String> additionalContext, WipValueLoader destinationValueLoaderParam, final EvaluateCallback callback, SyncCallback syncCallback) { if (destinationValueLoaderParam == null) { destinationValueLoaderParam = valueLoader; } final WipValueLoader destinationValueLoader = destinationValueLoaderParam; if (additionalContext != null && !additionalContext.isEmpty()) { WipContextBuilder contextBuilder = valueLoader.getTabImpl().getContextBuilder(); EvaluateHack evaluateHack = contextBuilder.getEvaluateHack(); return evaluateHack.evaluateAsync(expression, valueNameBuidler, additionalContext, destinationValueLoader, evaluateHackHelper, callback, syncCallback); } WipParamsWithResponse<DATA> params = createRequestParams(expression, destinationValueLoader); GenericCallback<DATA> commandCallback; if (callback == null) { commandCallback = null; } else { commandCallback = new GenericCallback<DATA>() { @Override public void success(DATA data) { JsVariable variable = processResponse(data, destinationValueLoader, valueNameBuidler); callback.success(variable); } @Override public void failure(Exception exception) { callback.failure(exception.getMessage()); } }; } WipCommandProcessor commandProcessor = valueLoader.getTabImpl().getCommandProcessor(); return commandProcessor.send(params, commandCallback, syncCallback); } private JsVariable processResponse(DATA data, WipValueLoader destinationValueLoader, ValueNameBuilder valueNameBuidler) { RemoteObjectValue valueData = getRemoteObjectValue(data); WipValueBuilder valueBuilder = destinationValueLoader.getValueBuilder(); if (getWasThrown(data) == Boolean.TRUE) { return WipContextBuilder.wrapExceptionValue(valueData, valueBuilder); } else { return valueBuilder.createVariable(valueData, valueNameBuidler); } } private final EvaluateHack.EvaluateCommandHandler<DATA> evaluateHackHelper = new EvaluateHack.EvaluateCommandHandler<DATA>() { @Override public WipParamsWithResponse<DATA> createRequest( String patchedUserExpression, WipValueLoader destinationValueLoader) { return createRequestParams(patchedUserExpression, destinationValueLoader); } @Override public JsVariable processResult(DATA response, WipValueLoader destinationValueLoader, ValueNameBuilder valueNameBuidler) { return processResponse(response, destinationValueLoader, valueNameBuidler); } @Override public Exception processFailure(Exception cause) { return cause; } }; protected abstract WipParamsWithResponse<DATA> createRequestParams(String expression, WipValueLoader destinationValueLoader); protected abstract RemoteObjectValue getRemoteObjectValue(DATA data); protected abstract Boolean getWasThrown(DATA data); static WipEvaluateContextBase<?> castArgument(JsEvaluateContext context) { try { return (WipEvaluateContextBase<?>) context; } catch (ClassCastException e) { throw new IllegalArgumentException("Incorrect evaluate context argument", e); } } static final EvaluateToMappingExtension EVALUATE_TO_MAPPING_EXTENSION = new EvaluateToMappingExtension() { @Override public void evaluateSync(JsEvaluateContext evaluateContext, String expression, Map<String, String> additionalContext, RemoteValueMapping targetMapping, EvaluateCallback evaluateCallback) throws MethodIsBlockingException { CallbackSemaphore callbackSemaphore = new CallbackSemaphore(); RelayOk relayOk = evaluateAsync(evaluateContext, expression, additionalContext, targetMapping, evaluateCallback, callbackSemaphore); callbackSemaphore.acquireDefault(relayOk); } @Override public RelayOk evaluateAsync(JsEvaluateContext evaluateContext, String expression, Map<String, String> additionalContext, RemoteValueMapping targetMapping, EvaluateCallback evaluateCallback, SyncCallback syncCallback) { WipEvaluateContextBase<?> contextImpl = WipEvaluateContextBase.castArgument(evaluateContext); return contextImpl.evaluateAsync(expression, additionalContext, evaluateCallback, syncCallback); } }; }