com.openfin.desktop.fdc3.FDC3Client Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of openfin-desktop-java-adapter Show documentation
Show all versions of openfin-desktop-java-adapter Show documentation
The Java API for OpenFin Runtime
package com.openfin.desktop.fdc3;
import java.lang.System;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CopyOnWriteArrayList;
import com.openfin.desktop.*;
import org.json.JSONArray;
import org.json.JSONObject;
import com.openfin.desktop.channel.AbstractServiceClient;
import com.openfin.desktop.channel.ChannelAction;
public class FDC3Client extends AbstractServiceClient {
private final static String Open = "OPEN";
private final static String FindIntent = "FIND-INTENT";
private final static String FindIntentsByContext = "FIND-INTENTS-BY-CONTEXT";
private final static String Broadcast = "BROADCAST";
private final static String RaiseIntent = "RAISE-INTENT";
private final static String AddContextListener = "ADD-CONTEXT-LISTENER";
private final static String AddIntentListener = "ADD-INTENT-LISTENER";
private final static String RemoveIntentListener = "REMOVE-INTENT-LISTENER";
private final static String GetDesktopChannels = "GET-DESKTOP-CHANNELS";
private final static String GetChannelByID = "GET-CHANNEL-BY-ID";
private final static String GetCurrentChannel = "GET-CURRENT-CHANNEL";
private final static String ContextAction = "RECEIVE-CONTEXT";
private final static String ChannelContextAction = "HANDLE-CHANNEL-CONTEXT";
private final static String IntentAction = "RECEIVE-INTENT";
private final static String ServiceChannelName = "of-fdc3-service-v1";
private final static String Fdc3ChannelNameKey = "fdc3ChannelName"; // in response of getRuntimeInfo
private static FDC3Client instance;
private CopyOnWriteArrayList contextListeners;
private ConcurrentHashMap channelContextMap; // channelId -> context listener
private ConcurrentHashMap intentMap; // intent -> intent listener
public synchronized static FDC3Client getInstance(DesktopConnection desktopConnection) {
if (instance == null) {
instance = new FDC3Client(desktopConnection);
}
return instance;
}
private FDC3Client(DesktopConnection desktopConnection) {
super(ServiceChannelName, desktopConnection);
this.contextListeners = new CopyOnWriteArrayList<>();
this.intentMap = new ConcurrentHashMap<>();
this.channelContextMap = new ConcurrentHashMap<>();
}
@Override
public void connect(AckListener ackListener) {
OpenFinRuntime runtime = new OpenFinRuntime(this.desktopConnection);
try {
runtime.getRuntimeInfo(new AckListener() {
@Override
public void onSuccess(Ack ack) {
JSONObject data = (JSONObject) ack.getData();
if (data.has(Fdc3ChannelNameKey)) {
FDC3Client.this.setChannelName(data.getString(Fdc3ChannelNameKey));
}
FDC3Client.super.connect(ackListener);
}
@Override
public void onError(Ack ack) {
ackListener.onError(ack);
}
});
} catch (Exception ex) {
logger.error("Error getting RuntimeInfo", ex);
DesktopUtils.errorAckOnException(ackListener, this, ex);
}
}
void serviceDispatch(String action, JSONObject actionPayload, AckListener ackListener) {
this.channelClient.dispatch(action, actionPayload, ackListener);
}
/**
* Launches/links to an application by name.
* @param name Application name
* @param context Context object that will be provided to the opened application via a contextListener
* @param ackListener AckListener for the request
*/
public void open(String name, Context context, AckListener ackListener) {
JSONObject payload = new JSONObject();
payload.put("name", name);
if (context != null) {
payload.put("context", context);
}
this.serviceDispatch(Open, payload, ackListener);
}
/**
* Publishes context to other apps on the desktop.
* @param context Context object
* @param ackListener AckListener for the request
*/
public void broadcast(Context context, AckListener ackListener) {
JSONObject payload = new JSONObject();
payload.put("context", context);
this.serviceDispatch(Broadcast, payload, ackListener);
}
private AppIntent parseAppIntent(JSONObject appIntentJson) {
JSONObject intentJson = appIntentJson.getJSONObject("intent");
IntentMetadata im = new IntentMetadata(intentJson.getString("name"), intentJson.getString("displayName"));
JSONArray appsJson = appIntentJson.getJSONArray("apps");
ArrayList apps = new ArrayList();
for (int i = 0; i < appsJson.length(); i++) {
JSONObject appObj = appsJson.getJSONObject(i);
apps.add(new AppMetadata(appObj.getString("name")));
}
return new AppIntent(im, apps);
}
/**
* Find out more information about a particular intent by passing its name, and optionally its context.
* @param intent Intent name
* @param context Context Object
* @param callback AckListener for the request
*/
public void findIntent(String intent, Context context, AsyncCallback callback) {
JSONObject payload = new JSONObject();
payload.put("intent", intent);
if (context != null) {
payload.put("context", context);
}
this.serviceDispatch(FindIntent, payload, new AckListener() {
@Override
public void onSuccess(Ack ack) {
JSONObject result = ack.getJsonObject().getJSONObject("data").getJSONObject("result");
callback.onSuccess(parseAppIntent(result));
}
@Override
public void onError(Ack ack) {
}
});
}
/**
* Find all the avalable intents for a particular context.
* @param context Context Object
* @param callback AckListener for the request
*/
public void findIntentsByContext(Context context, AsyncCallback> callback) {
JSONObject payload = new JSONObject();
payload.put("context", context == null ? null : context);
this.serviceDispatch(FindIntentsByContext, payload, new AckListener() {
@Override
public void onSuccess(Ack ack) {
System.out.println(ack.getJsonObject().toString());
JSONArray result = ack.getJsonObject().getJSONObject("data").getJSONArray("result");
ArrayList intents = new ArrayList();
for (int i=0; i callback) {
JSONObject payload = new JSONObject();
payload.put("intent", intent);
payload.put("context", context == null ? null : context);
payload.put("target", target);
this.serviceDispatch(RaiseIntent, payload, new AckListener() {
@Override
public void onSuccess(Ack ack) {
logger.info("raise intent onSuccess, response: {}", ack.getJsonObject().toString());
JSONObject dataObj = (JSONObject) ack.getData();
JSONObject result = dataObj.getJSONObject("result");
Object resultData = result.has("data") ? result.get("data") : null;
IntentResolution ir = new IntentResolution(result.getString("source"),resultData, result.getString("version"));
callback.onSuccess(ir);
}
@Override
public void onError(Ack ack) {
logger.info("raise intent onError, reason: {}", ack.getReason());
}
});
}
private void registerContextAction() {
logger.debug(String.format("Registering action %s", ContextAction));
this.channelClient.register(ContextAction, new ChannelAction() {
@Override
public JSONObject invoke(String action, JSONObject payload, JSONObject senderIdentity) {
Context context = Context.fromJson(payload.getJSONObject("context"));
for (ContextListener listener : contextListeners) {
listener.onContext(context);
}
return null;
}
});
}
private void registerChannelContextAction() {
logger.debug(String.format("Registering action %s", ChannelContextAction));
this.channelClient.register(ChannelContextAction, new ChannelAction() {
@Override
public JSONObject invoke(String action, JSONObject payload, JSONObject senderIdentity) {
String channelId = payload.getString("channel");
ContextListener listener = FDC3Client.this.channelContextMap.get(channelId);
if (listener != null) {
Context context = Context.fromJson(payload.getJSONObject("context"));
listener.onContext(context);
return null;
} else {
logger.debug(String.format("no channel listeners for %s", channelId));
}
return null;
}
});
}
synchronized void addChannelContextListener(String channelId, ContextListener contextListener) {
if (this.channelContextMap.get(channelId) == null) {
logger.debug(String.format("Registering action %s", ChannelContextAction));
this.channelContextMap.put(channelId, contextListener);
} else {
logger.debug(String.format("channel listeners already registered for %s", channelId));
}
}
private void registerIntentAction() {
logger.debug(String.format("Registering action %s", IntentAction));
this.channelClient.register(IntentAction, new ChannelAction() {
@Override
public JSONObject invoke(String action, JSONObject payload, JSONObject senderIdentity) {
String intent = payload.getString("intent");
Context context = Context.fromJson(payload.getJSONObject("context"));
IntentListener listener = FDC3Client.this.intentMap.get(intent);
JSONObject result = null;
if (listener != null) {
result = listener.onIntent(context);
}
return result;
}
});
}
@Override
protected void onChannelConnected() {
super.onChannelConnected();
registerContextAction();
registerChannelContextAction();
registerIntentAction();
}
/**
* Adds a listener for incoming context broadcast from the Desktop Agent.
* @param callback The context listener
* @param ackListener AckListener for the request
*/
public void addContextListener(ContextListener callback, AckListener ackListener) {
if (this.contextListeners.size() == 0) {
JSONObject payload = new JSONObject();
payload.put("id", this.channelName);
this.serviceDispatch(AddContextListener, payload, new AckListener() {
@Override
public void onSuccess(Ack ack) {
if (ack.isSuccessful()) {
FDC3Client.this.contextListeners.add(callback);
if (ackListener != null) {
ackListener.onSuccess(ack);
}
logger.debug("context listener registered");
} else if (ackListener != null) {
ackListener.onError(ack);
}
}
@Override
public void onError(Ack ack) {
logger.warn("unable to register context listener reason: {}", ack.getReason());
if (ackListener != null) {
ackListener.onError(ack);
}
}
});
} else {
FDC3Client.this.contextListeners.add(callback);
if (ackListener != null) {
ackListener.onSuccess(null);
}
}
}
public boolean removeContextListener(ContextListener listener) {
return this.contextListeners.remove(listener);
}
/**
* Adds a listener for incoming Intents from the Agent.
* @param intent Intent name
* @param listener The intent listener
* @param ackListener AckListener for the request
*/
public void addIntentListener(String intent, IntentListener listener, AckListener ackListener) {
if (this.intentMap.get(intent) == null) {
JSONObject payload = new JSONObject();
payload.put("intent", intent);
this.serviceDispatch(AddIntentListener, payload, new AckListener() {
@Override
public void onSuccess(Ack ack) {
if (ack.isSuccessful()) {
FDC3Client.this.intentMap.put(intent, listener);
if (ackListener != null) {
ackListener.onSuccess(ack);
}
logger.debug("intent {} listener registered", intent);
} else if (ackListener != null) {
ackListener.onError(ack);
}
}
@Override
public void onError(Ack ack) {
logger.warn("unable to register intent listener {}, reason: {}", intent, ack.getReason());
if (ackListener != null) {
ackListener.onError(ack);
}
}
});
} else {
JSONObject obj = new JSONObject();
obj.put("success", false);
obj.put("reason", "Intent listener already registered");
Ack ack = new Ack(obj, this);
logger.warn("unable to register intent listener {}, reason: {}", intent, ack.getReason());
if (ackListener != null) {
ackListener.onError(ack);
}
}
}
void removeIntentListener(String intent, IntentListener listener, AckListener ackListener) {
if (this.intentMap.get(intent) == listener) {
JSONObject payload = new JSONObject();
payload.put("intent", intent);
this.serviceDispatch(RemoveIntentListener, payload, new AckListener() {
@Override
public void onSuccess(Ack ack) {
}
@Override
public void onError(Ack ack) {
}
});
}
}
public void getChannelById(String id, AsyncCallback callback) {
JSONObject payload = new JSONObject();
payload.put("id", id);
this.serviceDispatch(GetChannelByID, payload, new AckListener() {
@Override
public void onSuccess(Ack ack) {
if (ack.isSuccessful()) {
JSONObject data = ack.getJsonObject().getJSONObject("data");
JSONObject result = data.getJSONObject("result");
if (id.equals(result.getString("id"))) {
Channel c = new Channel(id, FDC3Client.this);
if (result.has("name")) {
c.setName(result.getString("name"));
}
else if (result.has("visualIdentity")) {
JSONObject vid = result.getJSONObject("visualIdentity");
c.setName(vid.getString("name"));
}
callback.onSuccess(c);
} else {
logger.debug("channel not found: {}", id);
callback.onSuccess(null);
}
} else {
logger.debug("channel not found: {}", id);
callback.onSuccess(null);
}
}
@Override
public void onError(Ack ack) {
logger.info("raise intent onError, reason: {}", ack.getReason());
callback.onSuccess(null);
}
});
}
public void getDefaultChannel(AsyncCallback callback) {
this.getChannelById("default", callback);
}
}