2

I need to register a ColdFusion callback (using Lucee) that will be executed from within a Java class as follows:

(I stubbed out how I envision invoking the callback - in comments below)

package com.bonnydoonmedia.io;

import org.java_websocket.client.WebSocketClient;
import org.java_websocket.drafts.Draft_10;
import org.java_websocket.handshake.ServerHandshake;

import java.net.URI;

/*
 * author: Robert Munn
 * date: 3/15/15
 * 
 * WSClient.java
 * 
 * Simple extension of WebSocketClient by Too Tall Nate
 * 
 * based on example client at
 * 
 * https://github.com/TooTallNate/Java-WebSocket
 * 
 * License: Mozilla Public License 2.0
 * 
 */

public class WSClient extends WebSocketClient{

    public WSClient( URI serverUri , Draft_10 draft ) {
        super( serverUri, draft );
    }

    public WSClient( URI serverURI ) {
        super( serverURI );
    }

    public void connect(){
        super.connect();
    }

    public void send( String message ){
        super.send( message );
    }

    @Override
    public void onOpen( ServerHandshake handshakedata ) {
        System.out.println( "opened connection" );
        System.out.println( "ready state : " + super.getReadyState() );
        /* INVOKE THE CALLBACK HERE LIKE:
        callback({
            "action": "onOpen",
            "data": {}
        });
        */
    }

    @Override
    public void onMessage( String message ) {
        System.out.println( "received: " + message );
        /* INVOKE THE CALLBACK HERE LIKE:
        callback({
            "action": "onMessage",
            "data": {
                "message": message
            }
        });
        */
    }

    @Override
    public void onClose( int code, String reason, boolean remote ) {
        // The codecodes are documented in class org.java_websocket.framing.CloseFrame
        System.out.println( "Connection closed by " + ( remote ? "remote peer" : "us" ) );
        /* INVOKE THE CALLBACK HERE LIKE:
        callback({
            "action": "onClose",
            "data": {
            }
        });
        */
    }

    @Override
    public void onError( Exception ex ) {
        ex.printStackTrace();
        // if the error is fatal then onClose will be called additionally
        /* INVOKE THE CALLBACK HERE LIKE:
        callback({
            "action": "onMessage",
            "data": {
            }
        });
        */
    }
}

Creating the "object" in ColdFusion looks like this (this already works):

// create the websocket client
uriObject = createObject( "java", "java.net.URI" ).init("ws://local.websockets");
wsClient = CreateObject("java", "WSClient").init(uriObject);

Now I need to register a callback, and I'm thinking it would be done like this:

function void wsCallback (data) {

    switch(data.action) {
        case "onOpen":
            break;
        case "onClose":
            break;
        case "onMessage":
            break;
        case "onError":
            break;
    }

};

wsClient.setCallback(wsCallback);

The question is, how do I do the last part (setting the callback in the class)?

Redtopia
  • 4,947
  • 7
  • 45
  • 68
  • 1
    Since it is an abstract class, try using the [CFCProxy](https://helpx.adobe.com/coldfusion/developing-applications/using-web-elements-and-external-objects/integrating-jee-and-java-elements-in-cfml-applications/enhanced-java-integration-in-coldfusion.html). Create CFC with the desired functions ("onClose", etcetera). Then inside your java class, create an instance of that component using coldfusion.cfc.CFCProxy, and invoke the appropriate function, ie `CFCProxy yourInstance = new CFCProxy(cfcPath...); yourInstance.invoke("onClose", args)`. – Leigh Sep 22 '16 at 22:26
  • Hmmm... I haven't used CFCProxy before. I'll have to investigate. Thanks for the tip! – Redtopia Sep 22 '16 at 22:30
  • (Edit) Should be pretty simple. Nothing special on the CF side. In java, just crate and instance with `new CFCProxy(cfcPath...)` and `invoke(...)` and you should be good to go :) – Leigh Sep 22 '16 at 22:37
  • The examples I see use `import coldfusion.cfc.CFCProxy;` but I'm not sure where that will be located when compiling java targeted for Lucee. Any ideas? (BTW, I'm not very skilled in Java) – Redtopia Sep 22 '16 at 22:41
  • My bad. I missed the Lucee tag. Since CFCProxy should already be in the core classpath, try [this tip](http://stackoverflow.com/questions/35700231/how-to-identify-what-version-jar-is-running-under-coldfusion/37231805#37231805) to find out which jar contains that class. Just substitute `createObject("java", "coldfusion.cfc.CFCProxy")` for the "testClass". I tried it with Lucee 4.5 Express, and it said it is located in the /lib/ext/lucee.jar – Leigh Sep 22 '16 at 23:00
  • @Leigh - CFProxy seems to work nicely, but now I'm messing around with my class so that I can return a coldfusion struct, which I can't seem to figure out. If you have any ideas, check out http://stackoverflow.com/questions/39670241/how-do-i-return-a-coldfusion-struct-from-a-method-in-a-java-class-in-lucee. You can also answer this question and I'll be happy to accept the answer (at least until a better answer comes up! :) – Redtopia Sep 23 '16 at 22:09
  • Sure seems simple but I can't figure out how to create a Map, set the keys and return it. I was able to return a HashMap, which could probably work, but it's not a ColdFusion strict and doesn't show up like one. – Redtopia Sep 23 '16 at 23:05
  • *until a better answer comes up!* ... So we're going to the prom - unless your first choice says "yes" ;-) (Just joking). Seriously though, looks like Lucee has other (cool) options for interacting with the CF engine. I would be very curious find out a Lucee guru's opinion on this one. So if you find out more, do post it here. http://docs.lucee.org/guides/working-with-source/java-using-lucee-in-java.html – Leigh Sep 23 '16 at 23:12
  • @Leigh - yea, I saw this article that looks really promising: http://docs.lucee.org/guides/working-with-source/java-using-lucee-in-java.html. Unfortunately, I was running Lucee 4.5, and the code examples on this article didn't work. So I decided to upgrade to 5, and now I'm completely F'ED!!! The upgrade didn't go smoothly at all, and I'm dead in the water for the time being. – Redtopia Sep 23 '16 at 23:22
  • Heh, looks like we both arrived at the same article. Sorry to hear about the hosed install. Seems to be going around. I am trying to figure out why an app works only works on one out of two (theoretically) identical machines. – Leigh Sep 23 '16 at 23:34

1 Answers1

0

Since it is an abstract class, try using the CFCProxy. To use it create a CFC with the desired functions, ie "onClose", etcetera. Then inside your java class, import coldfusion.cfc.CFCProxy and create an instance of that component. Then invoke the appropriate function, ie

CFCProxy yourInstance = new CFCProxy("c:/path/to/yourComponent.cfc");
yourInstance.invoke( "onClose", args );

The CFCProxy class should already be in the core class path. If you are not sure where to find it, try this tip to find out which jar contains that class. Just substitute createObject("java", "coldfusion.cfc.CFCProxy") for the "testClass". I tried it with Lucee 4.5 Express, and it said it is located in {luccee_root}/lib/ext/lucee.jar.

NB: It looks like Lucee also has other (cooler) options for interacting with the CF engine from java.

Community
  • 1
  • 1
Leigh
  • 28,765
  • 10
  • 55
  • 103