Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 18 additions & 1 deletion java/org/cef/callback/CefQueryCallback.java
Original file line number Diff line number Diff line change
Expand Up @@ -4,22 +4,39 @@

package org.cef.callback;

import java.nio.ByteBuffer;

/**
* Interface representing a query callback.
*/
public interface CefQueryCallback {
/**
* Notify the associated JavaScript onSuccess callback that the query has
* completed successfully.
* @param response Response passed to JavaScript.
* @param response Response text passed to JavaScript.
*/
public void success(String response);

/**
* Notify the associated JavaScript onSuccess callback that the query has
* completed successfully.
* @param response Response buffer passed to JavaScript. May be null.
*/
public void success(ByteBuffer response);

/**
* Notify the associated JavaScript onFailure callback that the query has
* failed.
* @param error_code Error code passed to JavaScript.
* @param error_message Error message passed to JavaScript.
*/
public void failure(int error_code, String error_message);

/**
* Returns whether this callback is persistent and therefore whether
* {@link CefQueryCallback#success(String)} may be called multiple times.
* Persistent queries must be explicitly canceled, either from the browser
* or via {@link CefQueryCallback#failure(int, String)}.
*/
public boolean isPersistent();
}
30 changes: 28 additions & 2 deletions java/org/cef/callback/CefQueryCallback_N.java
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@

package org.cef.callback;

import java.nio.ByteBuffer;

class CefQueryCallback_N extends CefNativeAdapter implements CefQueryCallback {
CefQueryCallback_N() {}

Expand All @@ -16,7 +18,16 @@ protected void finalize() throws Throwable {
@Override
public void success(String response) {
try {
N_Success(getNativeRef(null), response);
N_Success(getNativeRef(null), response, isPersistent());
} catch (UnsatisfiedLinkError ule) {
ule.printStackTrace();
}
}

@Override
public void success(ByteBuffer response) {
try {
N_SuccessBinary(getNativeRef(null), response, isPersistent());
} catch (UnsatisfiedLinkError ule) {
ule.printStackTrace();
}
Expand All @@ -31,6 +42,21 @@ public void failure(int error_code, String error_message) {
}
}

private final native void N_Success(long self, String response);
@Override
public boolean isPersistent() {
return false;
}

private final native void N_Success(long self, String response, boolean persistent);
private final native void N_SuccessBinary(long self, ByteBuffer response, boolean persistent);
private final native void N_Failure(long self, int error_code, String error_message);
}

class CefQueryCallback_N_Persistent extends CefQueryCallback_N {
CefQueryCallback_N_Persistent() {}

@Override
public boolean isPersistent() {
return true;
}
}
23 changes: 22 additions & 1 deletion java/org/cef/handler/CefMessageRouterHandler.java
Original file line number Diff line number Diff line change
Expand Up @@ -9,18 +9,21 @@
import org.cef.callback.CefNative;
import org.cef.callback.CefQueryCallback;

import java.nio.ByteBuffer;

/**
* Implement this interface to handle queries. All methods will be executed on the browser process
* UI thread.
*/
public interface CefMessageRouterHandler extends CefNative {
/**
* Called when the browser receives a JavaScript query.
* Called when the browser receives a JavaScript text query.
*
* @param browser The corresponding browser.
* @param frame The frame generating the event. Instance only valid within the scope of this
* method.
* @param queryId The unique ID for the query.
* @param request The query text.
* @param persistent True if the query is persistent.
* @param callback Object used to continue or cancel the query asynchronously.
* @return True to handle the query or false to propagate the query to other registered
Expand All @@ -31,6 +34,24 @@ public interface CefMessageRouterHandler extends CefNative {
public boolean onQuery(CefBrowser browser, CefFrame frame, long queryId, String request,
boolean persistent, CefQueryCallback callback);

/**
* Called when the browser receives a JavaScript binary query.
*
* @param browser The corresponding browser.
* @param frame The frame generating the event. Instance only valid within the scope of this
* method.
* @param queryId The unique ID for the query.
* @param request The query direct buffer. Valid only for the scope of this method.
* @param persistent True if the query is persistent.
* @param callback Object used to continue or cancel the query asynchronously.
* @return True to handle the query or false to propagate the query to other registered
* handlers, if any. If no handlers return true from this method then the query will be
* automatically canceled with an error code of -1 delivered to the JavaScript onFailure
* callback.
*/
public boolean onQuery(CefBrowser browser, CefFrame frame, long queryId, ByteBuffer request,
boolean persistent, CefQueryCallback callback);

/**
* Called when a pending JavaScript query is canceled.
*
Expand Down
8 changes: 8 additions & 0 deletions java/org/cef/handler/CefMessageRouterHandlerAdapter.java
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@
import org.cef.callback.CefNativeAdapter;
import org.cef.callback.CefQueryCallback;

import java.nio.ByteBuffer;

/**
* An abstract adapter class for receiving message router events.
* The methods in this class are empty.
Expand All @@ -22,6 +24,12 @@ public boolean onQuery(CefBrowser browser, CefFrame frame, long queryId, String
return false;
}

@Override
public boolean onQuery(CefBrowser browser, CefFrame frame, long queryId, ByteBuffer request,
boolean persistent, CefQueryCallback callback) {
return false;
}

@Override
public void onQueryCanceled(CefBrowser browser, CefFrame frame, long queryId) {
return;
Expand Down
36 changes: 36 additions & 0 deletions java/tests/detailed/handler/MessageRouterHandlerEx.java
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,14 @@
import org.cef.callback.CefQueryCallback;
import org.cef.handler.CefMessageRouterHandlerAdapter;

import java.nio.ByteBuffer;

public class MessageRouterHandlerEx extends CefMessageRouterHandlerAdapter {
private final CefClient client_;
private final CefMessageRouterConfig config_ =
new CefMessageRouterConfig("myQuery", "myQueryAbort");
private CefMessageRouter router_ = null;
private boolean binary_direct_ = false;

public MessageRouterHandlerEx(final CefClient client) {
client_ = client;
Expand Down Expand Up @@ -47,6 +50,39 @@ public boolean onQuery(CefBrowser browser, CefFrame frame, long query_id, String
router_ = null;
callback.success("");
}
} else if (request.startsWith("doPersistent")) {
if (persistent) {
callback.success("Hello,");
callback.success("World!");
callback.failure(0, "Finished");
} else {
callback.failure(-1, "Request not marked as persistent");
}
} else {
// not handled
return false;
}
return true;
}

@Override
public boolean onQuery(CefBrowser browser, CefFrame frame, long query_id, ByteBuffer request,
boolean persistent, CefQueryCallback callback) {
if (request != null) {
int size = request.capacity();
boolean direct = (binary_direct_ = !binary_direct_);
ByteBuffer response = direct ? ByteBuffer.allocateDirect(size)
: ByteBuffer.allocate(size);
// reverse bytes
for (int i = 0; i < size; i++) {
byte b = request.get(i);
response.put(size - i - 1, b);
}
callback.success(response);
if (persistent) {
callback.failure(0, direct ? "Finished (direct)"
: "Finished (array)");
}
} else {
// not handled
return false;
Expand Down
50 changes: 50 additions & 0 deletions java/tests/detailed/handler/binding_test2.html
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,44 @@
});
}

function doPersistent() {
document.getElementById('persist').value = '';
window.cefQuery({
request: 'doPersistent',
persistent: true,
onSuccess: function(response) {
document.getElementById('persist').value += ' MESSAGE: [ ' + response + '];';
},
onFailure: function(error_code, error_message) {
document.getElementById('persist').value += ' FINISHED: ' + error_code + ' ' + error_message;
}
});
}

function doBinary() {
document.getElementById('binary').value = 'ORIGINAL: [';
const binaryData = new Uint8Array([10, 20, 30, 40, 50]);
for (let i = 0; i < binaryData.length; i++) {
document.getElementById('binary').value += ' ' + binaryData.at(i);
}
document.getElementById('binary').value += ' ];';
window.cefQuery({
request: binaryData.buffer,
persistent: true,
onSuccess: function(response) {
document.getElementById('binary').value += ' RESPONSE: [';
const echoedBinaryData = new Uint8Array(response);
for (let i = 0; i < echoedBinaryData.length; i++) {
document.getElementById('binary').value += ' ' + echoedBinaryData.at(i);
}
document.getElementById('binary').value += ' ];';
},
onFailure: function(error_code, error_message) {
document.getElementById('binary').value += ' FINISHED: ' + error_code + ' ' + error_message;
}
});
}

function execute(cmd) {
window.cefQuery({
request: cmd,
Expand Down Expand Up @@ -75,6 +113,18 @@ <h1>JavaScript Binding Test - Part 2</h1>
<input type="button" id="jcefOff" value="Disable myQuery" onclick="execute('disableExt');" />
<br/><input type="button" onclick="getJavaVersion();" value="Test"/>
<input type="text" id="result" size="80" readonly />
<br/><p>This button tests persistent queries. When the button is pressed, it clears the output,
and when it receives a success message, it appends it to the output. When it finally receives
a failure message, it appends the error_code followed by the error_message.</p>
<input type="button" onclick="doPersistent();" value="Persist"/>
<input type="text" id="persist" size="80" readonly />
<br/><p>This button tests binary queries. When the button is pressed, it clears the output and
replaces it with a representation of the binary data sent in the query. When it receives a
success message, it appends a similar representation of the binary data received (which has
been reversed by Java). When it finally receives a failure message, it appends the error_code
followed by the error_message.</p>
<input type="button" onclick="doBinary();" value="Binary"/>
<input type="text" id="binary" size="80" readonly />
</form>
</body>
</html>
Expand Down
46 changes: 45 additions & 1 deletion native/CefQueryCallback_N.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -26,11 +26,55 @@ JNIEXPORT void JNICALL
Java_org_cef_callback_CefQueryCallback_1N_N_1Success(JNIEnv* env,
jobject obj,
jlong self,
jstring response) {
jstring response,
jboolean persistent) {
CefRefPtr<CefQueryCallback> callback = GetSelf(self);
if (!callback)
return;
callback->Success(GetJNIString(env, response));
if (persistent)
return;
ClearSelf(env, obj);
}

JNIEXPORT void JNICALL
Java_org_cef_callback_CefQueryCallback_1N_N_1SuccessBinary(
JNIEnv* env,
jobject obj,
jlong self,
jobject response,
jboolean persistent) {
CefRefPtr<CefQueryCallback> callback = GetSelf(self);
if (!callback)
return;
jboolean isDirect = JNI_TRUE;
if (response)
JNI_CALL_BOOLEAN_METHOD(isDirect, env, response, "isDirect", "()Z");
if (isDirect != JNI_FALSE) {
callback->Success(GetJNIByteBufferData(env, response),
GetJNIByteBufferLength(env, response));
} else {
jobject responseArrayObj = nullptr;
jint responseOffset = 0;
jint responseLength = 0;
JNI_CALL_METHOD(env, response, "array", "()[B", Object, responseArrayObj);
JNI_CALL_METHOD(env, response, "arrayOffset", "()I", Int, responseOffset);
JNI_CALL_METHOD(env, response, "capacity", "()I", Int, responseLength);
jbyteArray responseArray = static_cast<jbyteArray>(responseArrayObj);
jsize responseArrayLength = env->GetArrayLength(responseArray);
if (responseLength >= 0 && responseLength <= responseArrayLength &&
responseOffset >= 0 && responseOffset < responseLength) {
// isCopy is ignored
jboolean isCopy = JNI_FALSE;
jbyte *responseBytes = env->GetByteArrayElements(responseArray, &isCopy);
callback->Success(static_cast<void*>(responseBytes + responseOffset),
static_cast<size_t>(responseLength));
// JNI_ABORT: no need to copy back the data
env->ReleaseByteArrayElements(responseArray, responseBytes, JNI_ABORT);
}
}
if (persistent)
return;
ClearSelf(env, obj);
}

Expand Down
17 changes: 15 additions & 2 deletions native/CefQueryCallback_N.h

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading