All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.openfin.desktop.Application Maven / Gradle / Ivy

There is a newer version: 11.0.2
Show newest version
package com.openfin.desktop;

import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CompletableFuture;


/**
 * An object representing the Application.
 * Allows the developer to execute, show and close an application,
 * as well as show and hide an icon on Desktop. Also provides access
 * to the Window object for the main application window to control
 * window state such as the ability to minimize, maximize, restore, etc.
 * @since 10/29/12
 */
public class Application {
    private final static Logger logger = LoggerFactory.getLogger(Application.class.getName());

    DesktopConnection connection;
    ApplicationOptions options;
    JSONObject noParamPayload,
            resizeToPayload,
            resizeByPayload,
            moveToPayload,
            moveByPayload,
            dockWindowPayload,
            eventListenerPayload;
    Window window;
    String uuid;
    EventListener trayIconClickListener;
    String manifestUrl;

    /**
     * Attaches an Application object to an application that already exists
     * @param uuid The UUID of the Application to wrap
     * @param connection Connection object to the AppDesktop
     * @return Application Object
     * @see DesktopConnection
     */
    public static Application wrap(String uuid, DesktopConnection connection) {
        return new Application(uuid, connection);
    }

    /**
     * Attaches an Application object to an application that already exists
     * @param uuid The UUID of the Application to wrap
     * @param connection Connection object to the AppDesktop
     * @see DesktopConnection
     */
    private Application(String uuid, DesktopConnection connection) {
        this.uuid = uuid;
        this.connection = connection;
        initialize();
    }

    /**
     * Application Constructor
     * @param options Settings of the application
     * @param connection Connection object to the AppDesktop.
     * @param listener function that is called if the method succeeds.
     * @see ApplicationOptions
     * @see DesktopConnection
     * @see AckListener
     */
    public Application(ApplicationOptions options, DesktopConnection connection, AckListener listener) {
        this.options = options;
        this.connection = connection;
        uuid = this.options.getUUID();
        initialize();
        connection.sendAction("create-application", this.options.getJsonCopy(), listener, this);
    }
    
	public static CompletableFuture createApplication(ApplicationOptions options, DesktopConnection connection) {
		return connection.sendActionAsync("create-application", options.getJsonCopy(), Application.class).thenApplyAsync(ack -> {
			if (ack.isSuccessful()) {
				Application app = Application.wrap(options.getUUID(), connection);
				return app;
			}
			else {
				throw new RuntimeException("error creating appliction, reason: " + ack.getReason());
			}
		});
	}

    /**
     *  Runs the application
     *
     * @throws DesktopException if application fails to run
     * @see DesktopException
     */
    public void run() throws DesktopException {
    	this.runAsync();
    }
    
    public CompletableFuture runAsync() {
        JSONObject payload = new JSONObject();
        payload.put("uuid", uuid);
        payload.put("manifestUrl", manifestUrl);
        return connection.sendActionAsync("run-application", payload, this).thenApplyAsync(ack -> {
        	if (ack.isSuccessful()) {
            	return Application.this;
        	}
        	else {
        		throw new RuntimeException("unable to run application, reason: " + ack.getReason());
        	}
        });
    }

    /**
     * Runs the application with a listener that gets called if the method succeeds
     * @param listener The listener that gets called if the method succeeds
     * @see  AckListener
     */
    public void run(AckListener listener) {
        JSONObject payload = new JSONObject();
        payload.put("uuid", uuid);
        payload.put("manifestUrl", manifestUrl);
        connection.sendAction("run-application", payload, listener, this);
    }

    /**
     * Restarts the application
     *
     * @throws DesktopException if application fails to restart
     * @see DesktopException
     */
    public void restart() throws DesktopException {
        connection.sendAction("restart-application", noParamPayload);
    }

    /**
     * Restarts the application with a listener that gets called if the method succeeds
     * @param listener The listener that gets called if the method succeeds
     * @see  AckListener
     */
    public void restart(AckListener listener) {
        connection.sendAction("restart-application", noParamPayload, listener, this);
    }

    /**
     * Closes the application and any child windows created by the application
     *
     * @throws DesktopException if application fails to close
     * @see DesktopException
     */
    public void close() throws DesktopException {
        connection.sendAction("close-application", noParamPayload);
    }

    /**
     * Closes the application with a listener that gets called if the method succeeds
     * @param listener The listener that gets called if the method succeeds
     * @see  AckListener
     * @deprecated use close() instead.
     */
    public void close(AckListener listener) {
        try {
            this.close();
        } catch (Exception ex) {
            logger.error("Error close app", ex);
        }
    }

    /**
     * Closes the application with a listener that gets called if the method succeeds
     * @param force When true the close can not be prevented through the window event 'close-requested'.  If force is false, AckListener is being ignored
     * @param listener The listener that gets called if the method succeeds
     * @throws DesktopException if application fails to close
     * @see  AckListener
     */
    public void close(Boolean force, AckListener listener) throws DesktopException {
        JSONObject payload = new JSONObject();
        try {
            if (force != null) {
                payload.put("force", force);
            }
            payload.put("uuid", getUuid());
            connection.sendAction("close-application", payload, listener, this);
        } catch (Exception e) {
            logger.error("Error closing application", e);
            throw new DesktopException(e);
        }
    }

    /**
     * Closes the application by terminating its process.
     *
     * @throws DesktopException if application fails to terminate
     * @see DesktopException
     */
    public void terminate() throws DesktopException {
        connection.sendAction("terminate-application", noParamPayload);
    }

    /**
     * Closes the application by terminating its process.
     * @param listener The listener that gets called if the method succeeds
     * @see  AckListener
     */
    public void terminate(AckListener listener) {
        connection.sendAction("terminate-application", noParamPayload, listener, this);
    }

    /**
     * Waits for a hanging application. This method can be called in response to an application "not-responding" to allow the application
     * to continue and to generate another "not-responding" message after a certain period of time.
     *
     * @throws DesktopException if application fails to wait for a hanging application
     * @see DesktopException
     */
    public void waitFor() throws DesktopException {
        connection.sendAction("wait-for-hung-application", noParamPayload);
    }

    /**
     * Waits for a hanging application. This method can be called in response to an application "not-responding" to allow the application
     * to continue and to generate another "not-responding" message after a certain period of time.
     * @param listener The listener that gets called if the method succeeds
     * @see  AckListener
     */
    public void waitFor(AckListener listener) {
        connection.sendAction("wait-for-hung-application", noParamPayload, listener, this);
    }

    /**
     *
     * Retrieves the JSON manifest that was used to create the application.
     * Invokes the error callback if the application was not created from a manifest.
     * AckListener is called and passed an Ack containing the JSONObject manifest
     * that was used to create the application.
     *
     * @param listener The listener that gets called if the method succeeds
     * @see  AckListener
     */
    public void getManifest(AckListener listener) {
        connection.sendAction("get-application-manifest", noParamPayload, listener, this);
    }


    /*
    public void dockWindow(String hwnd, String name) {
        try {
            connection.sendAction("dock-window", dockWindowPayload
                    .put("hwnd", hwnd)
                    .put("name", name));
        } catch (JSONException e) {
            e.printStackTrace();
        }
    }

    public void unDockWindow(String hwnd, String name, int x, int y) {
        try {
            connection.sendAction("undock-window", dockWindowPayload
                    .put("hwnd", hwnd)
                    .put("name", name)
                    .put("x", x)
                    .put("y", y));
        } catch (JSONException e) {
            e.printStackTrace();
        }
    }  */

    /**
     * Returns an instance to the main Window of the application.
     * @return the main Window
     */
    public Window getWindow() {
        return window;
    }

    /**
     * Get the ApplicationOptions object for the application
     * @return ApplicationOptions object
     */
    public ApplicationOptions getOptions() {
        return this.options;
    }

    /**
     * Get UUID of this Application
     * @return UUID
     */
    public String getUuid() {
        return uuid;
    }

    /**
     * Returns the applications connection object
     * @return DesktopConnection object
     * @see DesktopConnection
     */
    public DesktopConnection getConnection() {
        return connection;
    }

    /**
     *  Allocates and prepares internal JObjects and wraps the Applications main window
     */
    private void initialize() {
        try {
            noParamPayload = new JSONObject();
            resizeToPayload = new JSONObject();
            resizeByPayload = new JSONObject();
            moveToPayload = new JSONObject();
            moveByPayload = new JSONObject();
            dockWindowPayload = new JSONObject();
            noParamPayload.put("uuid", uuid);
            resizeToPayload.put("uuid", uuid);
            resizeByPayload.put("uuid", uuid);
            moveToPayload.put("uuid", uuid);
            moveByPayload.put("uuid", uuid);
            dockWindowPayload.put("uuid", uuid);
        } catch (JSONException e) {
            logger.error("Error initializing application", e);
        }
        window = new Window(this);
    }

    private void addEventListener(JSONObject subscriptionObject,
                                  EventListener listener,
                                  AckListener callback) {
        this.connection.addEventCallback(subscriptionObject,
                                                listener,
                                                callback,
                                                this);
    }

    /**
     * Registers an event listener on the specified event.
     * Supported system event types are:
     *     closed
     *     crashed
     *     error
     *     not-responding
     *     out-of-memory
     *     responding
     *     started
     *     run-requested
     * @param type  Event type
     * @param listener A listener that is called whenever an event of the specified type occurs
     * @param callback A function that is called if the method succeeds
     * @throws DesktopException if this methos fails to add event listener
     * @see EventListener
     * @see ActionEvent
     */
    public void addEventListener(String type,
                                 EventListener listener,
                                 AckListener callback) throws DesktopException {
        try {
            logger.debug("addEventListener " + type);
            if (eventListenerPayload == null) {
                eventListenerPayload = new JSONObject();
                eventListenerPayload.put("topic", "application");
                eventListenerPayload.put("uuid", getUuid());
            }
            eventListenerPayload.put("type", type);
            addEventListener(eventListenerPayload, listener, callback);
        } catch (Exception e) {
            logger.error("Error adding event listener", e);
            throw new DesktopException(e);
        }
    }

    /**
     * Removes a previously registered event listener from the specified event
     * @param type  Event type
     * @param listener A listener to remove
     * @param callback AckListener for the request
     * @throws DesktopException if this methd fails to remove an event listener
     * @see EventListener
     * @see ActionEvent
     */
    public void removeEventListener(String type,
                                 EventListener listener,
                                 AckListener callback) throws DesktopException {
        try {
            logger.debug("removeEventListener " + type);
            if (eventListenerPayload == null) {
                eventListenerPayload = new JSONObject();
                eventListenerPayload.put("topic", "application");
                eventListenerPayload.put("uuid", getUuid());
            }
            eventListenerPayload.put("type", type);
            this.connection.removeEventCallback(eventListenerPayload, listener, callback, this);
        } catch (Exception e) {
            logger.error("Error Removing event listener", e);
            throw new DesktopException(e);
        }
    }

    /**
     * Adds a customizable icon in the system tray and notifies the application when clicked
     *
     * @param iconUrl Image URL to be used as the icon
     * @param listener will be called whenever an event of the specified type occurs. It is passed an event object containing information related to the event
     * @param callback AckListener for the request
     * @throws DesktopException if this methed fails to set tray icon
     * @see EventListener
     * @see ActionEvent
     */
    public void setTrayIcon(String iconUrl, EventListener listener, AckListener callback) throws DesktopException {
        // Remove a prior listener if present.
        if (this.trayIconClickListener != null) {
            this.removeEventListener("tray-icon-clicked", this.trayIconClickListener, null);
        }
        // track this listner for future removal
        this.trayIconClickListener = listener;
        if (listener != null) {
            this.addEventListener("tray-icon-clicked", listener, callback);
        }
        try {
            JSONObject payload = new JSONObject();
            payload.put("uuid", getUuid());
            payload.put("name", getUuid());
            payload.put("enabledIcon", iconUrl);
            payload.put("disabledIcon", iconUrl);
            payload.put("hoverIcon", iconUrl);
            connection.sendAction("set-tray-icon", payload, callback, this);
        } catch (Exception e) {
            logger.error("Error setting tray icon", e);
            throw new DesktopException(e);
        }
    }

    /**
     * Removes the application’s icon from the tray.
     *
     * @param callback AckListener for the request
     * @throws DesktopException if this method fails to remove tray icn
     */
    public void removeTrayIcon(AckListener callback) throws DesktopException {
        // Remove a prior listener if present.
        if (this.trayIconClickListener != null) {
            this.removeEventListener("tray-icon-clicked", this.trayIconClickListener, null);
            this.trayIconClickListener = null;
        }
        try {
            JSONObject payload = new JSONObject();
            payload.put("uuid", getUuid());
            payload.put("name", getUuid());
            connection.sendAction("remove-tray-icon", payload, callback, this);
        } catch (Exception e) {
            logger.error("Error removing tray icon", e);
            throw new DesktopException(e);
        }
    }

    /**
     * Create a child window of this application
     *
     * @param windowOptions WindowOptions object for the requested child window.
     * @param callback AckListener for the request
     * @throws DesktopException if this method fails to create a child window
     */
    public void createChildWindow(WindowOptions windowOptions, AckListener callback) throws DesktopException {
        try {
            JSONObject payload = new JSONObject();
            payload.put("targetUuid", getUuid());
            payload.put("windowOptions", windowOptions.getJsonCopy());
            connection.sendAction("create-child-window", payload, callback, this);
        } catch (Exception e) {
            logger.error("Error creating child window", e);
            throw new DesktopException(e);
        }

    }

    /**
     * Retrieves an array of active window groups for all of the application's windows. Each group is represented as an array of wrapped fin.desktop.Windows.
     * An empty list is returned if the window is not in a group.
     * The calling window is included in the resulting List.
     *
     * @param groupHandler A class that receives a list of wrapped windows in the same group.
     * @see AsyncCallback
     * @param callback AckListener for the request
     * @see AckListener
     */
    public void getGroups(final AsyncCallback>> groupHandler, final AckListener callback) {
        if (groupHandler != null) {
            JSONObject payload = new JSONObject();
            payload.put("uuid", this.uuid);
            payload.put("crossApp", true); // cross app group supported
            connection.sendAction("get-application-groups", payload, new AckListener() {
                @Override
                public void onSuccess(Ack ack) {
                    List> list = new ArrayList>();
                    try {
                        JSONObject value = ack.getJsonObject();
                        if (value != null) {
                            JSONArray array = value.getJSONArray("data");
                            for (int i = 0; i < array.length(); i++) {
                                JSONArray subArray = array.getJSONArray(i);
                                if (subArray != null && subArray.length() > 0) {
                                    List subGroup = new ArrayList();
                                    list.add(subGroup);
                                    for (int k = 0; k < subArray.length(); k++) {
                                        JSONObject item = subArray.getJSONObject(k);
                                        subGroup.add(Window.wrap(item.getString("uuid"), item.getString("windowName"), connection));
                                    }
                                }
                            }
                        }
                        groupHandler.onSuccess(list);
                    } catch (Exception e) {
                        logger.error("Error processing group", e);
                    }
                }

                @Override
                public void onError(Ack ack) {
                    DesktopUtils.errorAck(callback, ack);
                }
            }, this);
        }
    }


    /**
     * Wraps an existing window using the specified name
     *
     * @param name The name of the window that is being wrapped
     * @return The wrapped window
     * @see Window
     */
    public Window wrapWindow(String name) {
        return Window.wrap(this.getUuid(), name, this.connection);
    }
    
    public static CompletableFuture createFromManifestAsync(String manifestUrl, DesktopConnection connection) {
		JSONObject payload = new JSONObject();
		payload.put("manifestUrl", manifestUrl);
		return connection.sendActionAsync("get-application-manifest", payload, Application.class).thenApplyAsync(ack -> {
			if (ack.isSuccessful()) {
				JSONObject appManifest = (JSONObject) ack.getData();
				JSONObject platformData = appManifest.optJSONObject("platform");
				String uuid = platformData == null ? appManifest.getJSONObject("startup_app").getString("uuid") : platformData.getString("uuid");
				Application app = Application.wrap(uuid, connection);
				app.uuid = uuid;
				app.manifestUrl = manifestUrl;
				return app;
			}
			else {
				throw new RuntimeException(ack.getReason());
			}
		});
    }
    
	/**
	 * Retrieves application's manifest and returns a wrapped application.
	 *
	 * @param manifestUrl
	 *            The URL of app's manifest
	 * @param callback
	 *            The callback that receives the wrapped {@link Application} object
	 * @see AsyncCallback
	 * @param listener
	 *            The AckListener for the request
	 * @see AckListener
	 * @param connection
	 *            The connection to openfin Runtime
     * @throws DesktopException if application fails to be created
     * @see DesktopException
	 */
	public static void createFromManifest(final String manifestUrl, final AsyncCallback callback,
			final AckListener listener, final DesktopConnection connection) throws DesktopException {
		createFromManifestAsync(manifestUrl, connection).thenAccept(app -> {
			if (app != null && callback != null) {
				callback.onSuccess(app);
			}
		});
	}

	/**
	 * Retrieves an list of wrapped fin.desktop.Windows for each of the
	 * application’s child windows
	 *
	 * @param callback
	 *            The callback that receives a list of wrapped {@link Window}
	 *            objects
	 * @see AsyncCallback
	 * @param listener
	 *            AckListener for the request
	 * @see AckListener
	 */
	public void getChildWindows(final AsyncCallback> callback, final AckListener listener) {
		AckListener mainCallback = null;
		if (callback != null) {
			mainCallback = new AckListener() {
				@Override
				public void onSuccess(Ack ack) {
					try {
						JSONArray data = (JSONArray) ack.getData();
						List list = new ArrayList<>();
						for (Object o : data) {
							String winName = (String) o;
							list.add(Window.wrap(uuid, winName, connection));
						}
						callback.onSuccess(list);
					}
					catch (Exception ex) {
						logger.error("Error calling onSuccess", ex);
					}
				}

				@Override
				public void onError(Ack ack) {
					DesktopUtils.errorAck(listener, ack);
				}
			};
		}
		connection.sendAction("get-child-windows", noParamPayload, listener, Application.class);
	}
	
	public CompletableFuture> getChildWindows() {
		return connection.sendActionAsync("get-child-windows", noParamPayload, this).thenApplyAsync(ack->{
			ArrayList windows = new ArrayList<>();
			if (ack.isSuccessful()) {
				JSONArray childWins = ack.getJsonObject().getJSONArray("data");
				for (int i=0; i callback, final AckListener listener) {
		AckListener mainCallback = null;
		if (callback != null) {
			mainCallback = new AckListener() {
				@Override
				public void onSuccess(Ack ack) {
					try {
						callback.onSuccess((JSONObject) ack.getData());
					}
					catch (Exception ex) {
						logger.error("Error calling onSuccess", ex);
					}
				}

				@Override
				public void onError(Ack ack) {
					DesktopUtils.errorAck(listener, ack);
				}
			};
		}
		connection.sendAction("get-info", noParamPayload, mainCallback, Application.class);
	}

	/**
	 * Retrieves UUID of the application that launches this application.
	 *
	 * @param callback
	 *            The UUID of the parent application
	 * @see AsyncCallback
	 * @param listener
	 *            AckListener for the request
	 * @see AckListener
	 */
	public void getParentUuid(final AsyncCallback callback, final AckListener listener) {
		AckListener mainCallback = null;
		if (callback != null) {
			mainCallback = new AckListener() {
				@Override
				public void onSuccess(Ack ack) {
					try {
						callback.onSuccess((String) ack.getData());
					}
					catch (Exception ex) {
						logger.error("Error calling onSuccess", ex);
					}
				}

				@Override
				public void onError(Ack ack) {
					DesktopUtils.errorAck(listener, ack);
				}
			};
		}
		connection.sendAction("get-parent-application", noParamPayload, mainCallback, Application.class);
	}

	/**
	 * Retrieves information about the custom icon the application previously set in the system tray via setTrayIcon().
	 *
	 * @param callback
	 *            tray icon info
	 * @see AsyncCallback
	 * @param listener
	 *            AckListener for the request
	 * @see AckListener
	 */
	public void getTrayIconInfo(final AsyncCallback callback, final AckListener listener) {
		AckListener mainCallback = null;
		if (callback != null) {
			mainCallback = new AckListener() {
				@Override
				public void onSuccess(Ack ack) {
					try {
						callback.onSuccess((JSONObject) ack.getData());
					}
					catch (Exception ex) {
						logger.error("Error calling onSuccess", ex);
					}
				}

				@Override
				public void onError(Ack ack) {
					DesktopUtils.errorAck(listener, ack);
				}
			};
		}
		connection.sendAction("get-tray-icon-info", noParamPayload, mainCallback, Application.class);
	}

	/**
	 * Determines if the application is currently running.
	 *
	 * @param callback
	 *            if the application is currently running
	 * @see AsyncCallback
	 * @param listener
	 *            AckListener for the request
	 * @see AckListener
	 */
	public void isRunning(final AsyncCallback callback, final AckListener listener) {
		AckListener mainCallback = null;
		if (callback != null) {
			mainCallback = new AckListener() {
				@Override
				public void onSuccess(Ack ack) {
					try {
						callback.onSuccess((Boolean) ack.getData());
					}
					catch (Exception ex) {
						logger.error("Error calling onSuccess", ex);
					}
				}

				@Override
				public void onError(Ack ack) {
					DesktopUtils.errorAck(listener, ack);
				}
			};
		}
		connection.sendAction("is-application-running", noParamPayload, mainCallback, Application.class);
	}

	/**
	 * Ferries a custom payload to the RVM.
	 *
	 * @param customData
	 *            the custom data
	 * @param listener
	 *            AckListener for the request
	 * @see AckListener
     * @deprecated use registerUser() instead.
	 */
	public void registerCustomData(JSONObject customData, final AckListener listener) {
	    logger.warn("Function is deprecated; use registerUser instead.");
	}

    /**
     * Manually registers a user with the licensing service. The only data sent by this call is userName and appName.
     *
     * @param username username to be passed to the RVM.
     * @param appName app name to be passed to the RVM.
     * @param listener
     *            AckListener for the request
     * @see AckListener
     */
    public void registerUser(String username, String appName, final AckListener listener) {
        JSONObject payload = new JSONObject();
        payload.put("uuid", getUuid());
        payload.put("userName", username);
        payload.put("appName", appName);
        connection.sendAction("register-user", payload, listener, this);
    }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy