The Latest version of documentation can be found on Glue42 Docs.
Using Java Glue42 Library
The Java Glue42 library provides an easy way to make your enterprise Java applications Glue42 enabled.
Installation
You can use java-glue42 in the same way as any standard Java library.
Java Glue42 requires JDK 8+(Java SE 8+) and is JDK 9+ ready.
Maven
<?xml version="1.0" encoding="utf-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.example</groupId>
<artifactId>myproject</artifactId>
<version>0.0.1-SNAPSHOT</version>
<properties>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
</properties>
<dependencies>
<dependency>
<groupId>com.glue42</groupId>
<artifactId>java-glue42-shaded</artifactId>
<version>1.4.5</version>
</dependency>
</dependencies>
</project>
Quick Start
import com.tick42.glue.Glue; (1)
try (Glue glue = Glue.builder().build()) (2)
{
System.out.println(glue.version()); (3)
}
| 1 | First import glue package |
| 2 | Glue is the main entry point of the sdk. It is thread-safe and you should create a single instance (per glue application) and share it throughout your code |
| 3 | We get the Glue version string |
Always close the Glue instance once you are done with it, in order to free up underlying resources
(ws connections, thread pools…).
This example uses try-with-resources block because Glue extends AutoCloseable, in a real application,
you will probably call close or closeAsync explicitly.
Configuration
To configure Java Glue42 you can use .conf files, .properties files, .json files
and system properties to externalize your configuration.
Here is an example minimal glue.conf file:
glue {
application: "My Java App"
}
Glue.builder().withApplicationName("My Java App").build();
Application Definition
To add your Java application to the Launcher application you need to define a configuration file and add it to application config store.
By default when running in file mode the store is located at %LocalAppData%\Tick42\GlueDesktop\config\apps.
Here is an example:
[
{
"title": "Java Example",
"type": "exe", (1)
"name": "java-example",
"icon": "https://enterprise-demos.tick42.com/resources/icons/w2.jpg",
"details": {
"path": "", (2)
"command": "java", (3)
"parameters": "-jar example.jar", (4)
"mode": "tab"
}
}
]
| 1 | type should be exe |
| 2 | path is the path to the application - relative or absolute |
| 3 | command is the actual command to execute (java) |
| 4 | parameters holds command line arguments |
| Application definitions should be a valid JSON file, you should either use forward slash or the escape backslash |
You can find detailed information about the application definitions in Configuration documentation.
Application Shutdown
When initializing Glue42, you can pass an event listener that will notify your application when it should be shutting down. This is useful when your app/process is not started directly by Glue42, but rather by Glue42 invoking a script/batch file or another application that in turn starts your application. With this listener you can properly shut down your application, free resources, etc.
import com.tick42.glue.Glue; (1)
Glue.builder()
.withShutdownRequestListener(glue -> {
System.out.println("Starting shutdown procedure...");
glue.closeAsync();
}) (2)
.build();
| 1 | First, import the Glue42 package. |
| 2 | Pass an event listener for when Glue42 is about to shut down. |
Interop
Overview
The Interop API enables applications to:
-
offer functionality to other applications (JavaScript and native) by registering Interop methods
-
discover applications which offer methods
-
invoke (call) methods on the user’s desktop and across the network
-
stream and subscribe to real-time data using the streaming API
Applications that offer methods and/or streams are called Interop servers, and applications which consume them Interop clients, and collectively - Interop instances.
Instance
Any application instance is identified by its Interop Instance, which is a set of known key-value pairs, uniquely identifying an application.
Here’s an example:
| Key | Example | Description |
|---|---|---|
application |
Client Portfolio |
Application name |
region |
TICK42 |
e.g. EU, US, AP |
environment |
DEMO |
e.g. DEV, SIT, UAT, PROD |
machine |
Lambda |
User’s machine name |
pid |
2864 |
Process ID |
user |
duke |
Currently logged user |
Method Registration
Register Methods
To offer a method to other applications call glue.interop().register(),
passing method’s definition and a callback to handle client invocations.
glue.interop().<Map<String, Object>, Map<String, Object>>register(
MethodDefinition.builder("Sum").withSignature("int a, int b", "int answer").build(),
(arg, caller) -> {
int a = (Integer) arg.get("a");
int b = (Integer) arg.get("b");
return Collections.singletonMap("answer", a + b);
});
Once a method is registered, it can be invoked from any app (web, native or java), that is Glue-enabled.
Method Definition
The method definition describes the Interop method your application is offering. It has following properties, required ones in bold:
| Name | Description |
|---|---|
name |
Name of the Method, e.g. OpenClientPerformance |
accepts |
Signature, describing the parameters that the method expects |
returns |
Signature, describing the properties of the object the method returns |
displayName |
Human-readable name of the method, e. g. Open Client Performance |
description |
Description of what method does, useful for documentation purposes, e.g. Launches or activates the Client Performance application |
objectTypes |
Entities this method is meant to work on, e.g. party(client, prospect, lead), instrument, order etc. |
It’s a good idea to specify displayName and description when defining a method.
These can be used by generic UI or by your own applications.
Signatures
The signature of a method is a comma-delimited string of parameters, defined as follows:
type [array_modifier] [optional_modifier] parameter_name [composite_schema] [description]
Where type is one of Bool, Int, Long, Double, String, DateTime, Composite
| Signature | Explanation |
|---|---|
|
|
|
|
|
|
Composite is a structure which contains one or more fields of type:
-
scalar (bool, int, etc)
-
array of scalars
-
a composite (nested structure)
-
an array of composites
Using Composite you can define almost any non-recursive, non-self-referential strucuture.
Method Invocation
Invoking Methods
To invoke a method offered by other applications, call glue.interop().invoke(),
passing method’s name and arguments.
Then use the returned future to receive result or an error.
Map<String, Object> arg = new HashMap<>();
arg.put("a", 37);
arg.put("b", 5);
glue.interop().invoke("Sum", arg)
.thenAccept(result ->
result.getReturned()
.ifPresent(r -> System.out.println(r.get("answer"))))
.toCompletableFuture().join();
Multiple Responses
Invoking a method on multiple Interop instances produces multiple responses.
This is how you can iterate over all of the responses:
result.forEach(r -> {
if (r.getStatus().isSuccess())
{
System.out.printf("success:%s%n", r.getReturned().orElseGet(Collections::emptyMap));
}
else
{
System.out.printf("error:%s%n", r.getStatus().message().orElse(null));
}
});
When invocation result has multiple responses the result’s hasMultipleResponses() will return true.
|
Discovery
Streaming
Overview
Interop stream can be used by your application to:
-
publish events which can be observed by other applications or provide real-time data (e.g. market data, news alerts, notifications etc.) to other applications, by publishing to Interop stream
-
receive and react to the above events and data by creating an Interop stream subscription
We call applications which create and publish to Interop Streams publishers, and applications which subscribe to Interop Streams subscribers. An application can be both.
Interop Streams are used extensively in Glue42 Desktop products and APIs.
Receiving data
Subscribing to a Stream
Subscribing to a streaming method is achieved by invoking glue.interop().stream().
glue.interop()
.stream("MarketData.LastTrades",
Collections.singletonMap("symbol", "ORCL"))
.thenAccept(stream -> stream.subscribe(new StreamSubscriber<Map<String, Object>>() {
@Override
public void onData(ServerMethod method, Map<String, Object> data) {
// do something with the data
}
}));
Closing Stream Subscription
To close a stream subscription invoke close() or closeAsync() method on the subscription reference
returned by subscribe() method.
AsynchronousCloseable subscription =
stream.subscribe(new StreamSubscriber<Map<String, Object>>() {});
subscription.closeAsync();
Getting Notified when a Subscription is Closed
At any time, a stream subscription can be closed either because the publisher shutting down or due to an error.
stream.subscribe(new StreamSubscriber<Map<String, Object>>()
{
@Override
public void onSubscribe(StreamSubscription subscription)
{
subscription.onClose().thenRun(() -> {
// called when the subscription is closed
});
}
@Override
public void onFailed(ServerMethod method, String reason)
{
// called if the subscription request is rejected
}
});
Publishing Data
To start publishing data, you need to register an Interop Stream by calling glue.interop().register() and provide
a method definition and stream subscription request handler.
glue.interop()
.register(MethodDefinition.forName("Clock"),
StreamSubscriptionRequestHandler.accept())
.thenAccept(stream -> {
Map<String, Object> data =
Collections.singletonMap("CurrentTime", Instant.now().toEpochMilli());
// will send data to all branches, as no branch is specified
stream.send(data);
});
StreamSubscriptionRequestHandler.accept() will accept all subscription request
on the default branch (more on that later).
Handling Subscription Requests
To control how you application accepts or rejects stream subscription requests by specifying custom handler.
This handler receives the request as argument and must return a StreamConsumer instance via
invoking accept(), acceptOn() or reject() methods of the request.
glue.interop()
.<Map<String, Object>>register(
MethodDefinition.builder("MarketData.LastTrades")
.withObjectType("Symbol")
.build(),
request -> {
String app = request.getCaller().getApplication();
String symbol = (String) request.getArg().get("Symbol");
if (symbol != null)
{
System.out.printf("Accepting %s subscription on %s%n", app, symbol);
return request.acceptOn(symbol);
}
else
{
System.out.printf("Rejecting %s symbol not specified%n", app);
return request.reject("Symbol not specified");
}
}
);
Handling New or Removed Consumers
To track when a consumer is added and/removed StreamSubscriptionRequestHandler provides
onAdded() and onRemoved() sugar methods to compose callbacks.
glue.interop()
.register(
MethodDefinition.builder("MarketData.LastTrades")
.withObjectType("Symbol")
.build(),
StreamSubscriptionRequestHandler
.<Map<String, Object>>accept((arg, caller) -> (String) arg.get("Symbol"))
.onAdded(consumer -> {
// called when new consumer subscription is accepted
})
.onRemoved(consumer -> {
// called when a consumer subscription is removed
})
);
In order to use those methods you need an instance of type StreamSubscriptionRequestHandler.
One way to achieve this is to not use lambda but one of the static factory methods provided.
Following fragment creates a handler that is equivalent (if you ignore logging) with the one provided in a previous section.
StreamSubscriptionRequestHandler
.<Map<String, Object>>accept((arg, caller) -> (String) arg.get("Symbol"))
StreamConsumer reference can be used to
-
access request parameters and caller instance -
getArg()andgetCaller() -
inspect branch on which consumer was accepted -
getBranch() -
push data directly to a consumer (unicast) -
send() -
close the subscription forcefully -
close()orcloseAsync()
Multicast Using Branches
A single stream supports one or multiple named sub-streams that are called branches. In such cases, where it doesn’t make sense for a stream to be split into multiple sub-streams a default branch is used.
The stream reference is of type StreamProducer and can be used to:
-
list all available branches:
Map<String, StreamBranch> allBranches = stream.getBranches();
-
list all stream consumers, regardless of the branch they are on:
List<StreamConsumer<?>> allConsumers = stream.getConsumers();
If your stream publishing code uses branches (e.g. creates a branch for each unique set of subscription arguments and associates the consumers with that branch), whenever a data arrives from your underlying source, you’ll want to use the branch to publish data instead of manually walking all consumers and sending data to the interested clients.
String branchKey = "Providers";
StreamBranch branch = stream.getBranches().get(branchKey);
if (branch != null)
{
branch.push(data);
System.out.printf("Pushed data to all subscribers on branch \"%s\"!%n", branch.getKey());
}
else
{
System.out.printf("Branch \"%s\" does not exist!%n", branchKey);
}
Intents
Raising Intents
To raise an Intent, use the raise() method:
glue.intents().raise("ShowChart");
The raise() method accepts an Intent name as a String or an IntentRequest as argument.
Target Intent Handlers
When raising an Intent, optionally target one or more IntentHandler instances using the withTarget() method
of the IntentRequest builder:
Intent intent = glue.intents().all()
.toCompletableFuture().join()
.get("ShowChart");
IntentHandler intentHandler = intent.getHandlers().get(0);
IntentRequest intentRequest =
IntentRequest.intent(intent.getName())
.withTarget(IntentTarget.application(intentHandler.getApplicationName()))
.build();
glue.intents().raise(intentRequest);
The IntentTarget can be created using one of the following factory methods:
-
startNew()- will start a new instance of the first available Intent handler; -
reuse()- will reuse the first available running instance of an Intent handler or fallback tostartNew()if there are no running instances available; -
application(String)- will start a new instance of a specific Intent handler application; -
instance(String)- will reuse a specific running instance of an Intent handler;
The default value for the Intent request target is startNew() when an Intent Handler application is available.
If the Intent has only been registered dynamically, the default value is reuse().
Context
Passing Initial Context
To pass initial context to the Intent handler, use the withContext(String, T) method of the IntentRequest builder.
Map<String, Object> contextData =
Collections.singletonMap("data",
Collections.singletonMap("selectedClientID", 1));
Map<String, Object> options = new LinkedHashMap<>();
options.put("width", 300);
options.put("height", 200);
glue.intents().raise(
IntentRequest.intent("ShowChart")
.withTarget(IntentTarget.startNew())
.withContext(
"Instrument", // contextType
contextData)
.withOptions(options)
.build()
);
The withOptions(Map<String,Object>) method of the IntentRequest builder is used to pass custom application startup
options to the Intent handler.
Handling Context Updates
To handle the context data passed when an Intent is raised and targeted at your application, use the
addIntentListener(String, IntentContextHandler) method.
glue.intents().addIntentListener("ShowChart", context -> {
context.getType().ifPresent(contextType -> {
switch (contextType) {
case "Instrument": {
Map<String, Object> data = context.getData();
// Application specific logic for handling the new context data
break;
}
}
});
return Collections.emptyMap(); // optionally return result to the caller
});
Registering Intents at Runtime
To register an Intent at runtime, use addIntentListener(IntentListenerRequest, Function<IntentContext, T>) method.
IntentListenerRequest<Map<String, Object>> intent =
IntentListenerRequest.intent("ShowChart", ReifiedType.OBJECT_MAP)
.withContextTypes(Collections.singletonList("Instrument"))
.withDisplayName("Instrument Chart")
.build();
glue.intents().addIntentListener(intent, (context) -> {
context.getType().ifPresent(contextType -> {
switch (contextType) {
case "Instrument": {
Map<String, Object> data = context.getData();
// Application specific logic for handling the new context data
break;
}
}
});
return Collections.emptyMap(); // optionally return result to the caller
});
Window Management
Overview
Sticky Windows allows to make windows sticky, so they can stick together forming groups that can move, minimize and maximize together.
The window management API is exposed in glue.windows(), and gives following features,
many of which not found in traditional Java GUI frameworks:
-
create metro/flat or tab windows
-
control and customize the chrome of these windows
-
visibility: e.g. create hidden windows, show them later
-
size: set minimum and/or maximum bounds
-
control what the user can do with the windows, e.g. allow a window to be sticky
-
add custom buttons and react to user clicking these
-
organize windows into tabs which the user can tear off
-
Making a Window Sticky
Registering a Swing Window
WindowManager windows = glue.windows();
WindowHandle<JFrame> handle = windows.getWindowHandle(frame); (1)
windows.register(handle) (2)
.thenAccept(window ->
frame.addWindowListener(new WindowAdapter()
{
@Override
public void windowClosing(WindowEvent e)
{
window.closeAsync(); (3)
}
}));
| 1 | Get window handle |
| 2 | Register window |
| 3 | Unregister window on close |
Currently, Glue42 Windows requires the underlying native handle (hwnd in case of Windows) to be initialized and
attached to the JFrame before the window can be registered. This is now achieved internally through Glue32 Windows.
Window Types
Glue supports following window modes: flat and tab.
The window type is controlled by the mode window option, which can be specified in the application definition or
during the register() call
glue.windows().register(handle, options -> options.mode(WindowMode.FLAT));
Controlling the Window
Once an application window is registered, Glue42 Windows will accept full control over the window positioning, sizing and visibility. The application shouldn’t use native methods (for example, Swing calls) to control the window as it will interfere with the Glue42 window management.
Glue provides several SW aware methods that should be used when direct control is required:
Frame Buttons
You can put extra buttons in the frame area of the window and handle clicks for those buttons.
Adding Button
Use addFrameButton method to add a new button:
window.addFrameButton("search-button",
ButtonOptions.builder()
.toolTip("Search")
.order(1)
.image(new byte[0]) // needs to be a valid image
.build())
.thenRun(() -> System.out.println("created button"));
Window hibernation/resume
You can subscribe for when the layout of your application is suspended/hibernated, so you can for example limit your resource usage while your application isn’t being used. You can also subscribe when your application is restored/resumed, so you can bring it back to it’s functional state. An example of limiting your resource usage could be for you to unsubscribe from receiving data updates and such.
With both events you’ll get the layout name and the meta data for that layout, if any.
Application Management
Overview
The Application Management API provides a way to manage Glue42 Desktop applications. Starting an application through the API returns an instance object that can be used to manage it.
ApplicationInstance - A running copy of an application within Glue42. The API provides a way to stop an application instance.
Registering a function through the API allows you to react when glue desktop wants to start a child application instance. Usually you will register a new window through the Windows API.
ApplicationInstanceHandler - A handler function that will be invoked when child application needs to be started.
Listing Applications
To list all available applications for the current user, use the applications() method:
glue.appManager().applications();
The applications() method returns a Map<String, ApplicationInstance> result containing the available instances keyed by application name.
Starting applications
To start an application use the start() method:
glue.appManager().start("clientlist")
.whenComplete((instance, error) -> {
if (error != null) {
// application failed to start
}
});
You can also pass context (an application-specific object that will be available in the new app) or override any of the pre-configured window settings:
glue.appManager().start("clientcontact", Collections.singletonMap("selectedUser", 2));
Listing running instances
To list all running instances of an application, use the instances() method:
glue.appManager().instances();
The instances() method returns a Collection<ApplicationInstance> result containing all running application instances.
Stopping instances
To stop a running instance use close() or closeAsync() method:
instance.closeAsync();
Multi Window Apps
Java Glue42 offers support for applications consisting of multiple windows. Each child window can be registered in the context of a child Glue42 Application that you can save and restore in a Layout, start directly from the Glue42 toolbar, etc.
The following example demonstrates how to register an ApplicationInstanceHandler using the registerInstanceHandler() method.
It will be invoked when a child window of the specified application is started.
The handler in the example registers the child window as a Glue42 Window using a WindowRegistration builder.
When the child window has been registered, it starts to listen for context updates using its onContextUpdated() method.
Finally, when a save is requested, the child window will save its current context using the addSaveListener() method in order to be able to retrieve it later when the Layout is restored:
glue.appManager().registerInstanceHandler("my-child-window", applicationInstance -> {
glue.windows().register(
WindowRegistration.builder(glue.windows().getWindowHandle(childFrame))
.withInstanceId(applicationInstance.getId())
.build()
).thenAccept(window ->
window.onContextUpdated(e ->
{
int selectedIndex = (Integer) e.getContext().getOrDefault("SelectedIndex", -1);
selector.setSelectedIndex(selectedIndex);
}));
glue.layouts().addSaveListener(applicationInstance.getId(), request ->
Collections.singletonMap("SelectedIndex", selector.getSelectedIndex()));
});
Layouts
Layouts Overview
Layouts allow you to save the layouts of any set of applications running in Glue Desktop as a named layout and later restore it.
You can access the API through the following entry point:
glue.layouts();
Global Layouts
Global saving and restoring is an operation in which all applications running on a user’s desktop are saved to a named Layout which can later be restored.
Saving a Global Layout
To save a global Layout use glue.layouts().save() method and specify a name for the Layout:
CompletionStage<Void> layout = glue.layouts().save(options -> options
.withName("Name of Layout")
.withType(LayoutType.GLOBAL)
);
| If a Layout with this name already exists it will be replaced. If a name is not specified, a random name will be generated. |
Application’s default layouts
When an application is started from the Toolbar, the initial size and position is defined in the application properties. Users often want to place it at an alternative position and so move it. GlueDesktop remembers the last location of a window and use that as the new start position.
Saving the last position is enabled by default for all applications (single windows or activities), but can be disabled per application by configuration.
Also if the user holds Shift key while starting an application it will appear on default screen position (as defined in properties) – this does not require change in AppManager.
Managing Layouts
Listing Layouts
To get a collection of all Layouts, use the list() method:
Collection<Layout> layouts = glue.layouts().list();
Exporting Layouts
To export all Layouts for the current user, use the exportLayouts() method:
CompletionStage<Collection<Layout>> exportedLayouts = glue.layouts().exportLayouts();
Importing Layouts
You can import collections of Layouts by either merging them with the existing ones, or replacing the existing ones.
Use the importLayouts() method and pass a collection of Layouts and import mode (MERGE or REPLACE):
CompletionStage<Void> importLayouts = glue.layouts().importLayouts(Collections.emptyList(), LayoutImportMode.REPLACE);
Saving Custom Data
Application can store custom data ina saved Layout. When the Layout is restored the custom data is also restored and returned to the applications.
Currently, the custom data can only be the window context. When the Layout is restored, the context of the window in the Layout will also be restored if it has been saved previously.
To save custom data, applications can subscribe for Layout save requests using the addSaveListener().
The LayoutSaveHandler passed as argument will be invoked when a Layout save is requested.
The handler receives a LayoutSaveRequest object as an argument from which the layout name and type can be extracted.
It must return a Map<String, Object> containing pairs of context property names and their values:
Map<String, Object> context = new HashMap<>();
context.put("gridWidth", 420);
context.put("gridHeight", 42);
glue.layouts().addSaveListener((request) -> context);
Channels
Overview
The Channels API enables users to dynamically group windows, instructing them to work over the same shared data.
When two windows are on the same channel they share a context data, which they can monitor and/or update.
A context data object can contain different types of data, e.g. RIC symbol, ClientID and AccountID
Map<String, Object> data = new LinkedHashMap<>();
data.put("RIC", "BMW.GR");
data.put("ClientID", 235399);
data.put("AccountID", "X2343");
Enable Channels for a Window
To add the channel selection to your window you need to enable the channel window option:
glue.windows().register(handle, options -> options.channel())
Create Channel Context
ChannelContext<Map<String, Object>> channelContext = glue.channels().create(window);
Subscribe for Channel Data
When your application wants to track the current channel and its data it should use the subscribe() method:
channelContext.subscribe((ChannelContextDataSubscriber<Map<String, Object>>) (channel, data) -> {
// each time channel context data is updated this method will be invoked
});
Shared Contexts
Listing All Available Contexts
A shared context object is a Map containing cross application data.
You can access all available context objects in order to manipulate them:
Subscribing for a Context
To subscribe for shared context updates, use the glue.contexts().subscribe() call, passing the name of the desired
context object:
glue.contexts().subscribe("app-styling")
.thenAccept(context -> context.data(data -> {
// use context data here
}));
If the specified shared context object does not exist, it will be created.
In the example above, the changes to the context object can be handled in the context.data(data → {}) callback.
Updating a Context
You can also update a shared context object by using glue.contexts().update() and passing as a first parameter the
name of the context object you want to update, and as a second parameter - a Map<String, Object> with the delta
values:
glue.contexts().update("app-styling", Collections.singletonMap("backgroundColor", "red"));
If the key you pass in the Map object exists in the shared context object, it will be overwritten with the new value.
If it does not exist, it will be created. If the value of a key in the Map you pass to glue.contexts().update() is
null, then that key will be deleted from the shared context object.
Let’s say you have subscribed to a shared context named "app-styling", which already has two entries -
"backgroundColor", "red" and "alternativeColor", "yellow".
In the example below:
-
"backgroundColor"will be overwritten with a new value -"blue"; -
"alternativeColor"will be deleted from the shared context object; -
"borderColor"will be created as a new key in the shared context object and its value will be set to"grey";
glue.contexts()
.subscribe("app-styling")
.thenAccept(context -> {
context.data(data -> {
// use context data here
});
Map<String, Object> delta = new HashMap<>();
delta.put("backgroundColor", "blue");
delta.put("alternativeColor", null);
delta.put("borderColor", "grey");
context.update(delta);
});
Notifications
Raising Notifications
To raise a notification on user’s desktop, first create a Notification instance
Notification alert = glue.notifications()
.create("Example", notification -> notification.title("Hello from Java Glue42"));
and then call the raise() method
alert.raise(NotificationSeverity.LOW);
Actions
Notifications can contains actions (usually displayed as buttons in the UI) that the user can execute when he/she sees the notification. Executing an action results in invoking an interop method. The interop method can be registered by the notification publisher or any other application that can handle the action.
The handler of the interop action can also receive parameters, specified by the publisher of the notification.
In following example we add Accept and Reject actions,
passing an id parameter to the first action:
glue.interop().register("NotificationAccepted", (arg, caller) -> Collections.emptyMap());
glue.interop().register("NotificationRejected", (arg, caller) -> Collections.emptyMap());
glue.notifications()
.create("Example", notification -> notification
.action("NotificationAccepted", "Accept", Collections.singletonMap("id", 42))
.action("NotificationRejected", "Reject"));
Toast Click
When raising a notification you can specify what happens when the user clicks on the notification toasts. By default this will show the build-in notification details view, but you can replace that with invoking an interop method.
In following example, when user clicks on the notification toast the DetailsHandler interop method will be invoked
glue.notifications()
.create("Example",notification -> notification.details("DetailsHandler"));
Office
Prerequisites
The Outlook integration requires the Glue42 Outlook addin to be installed and running.
Composing Emails
While there’s no technical limitation for the Glue Outlook addin to send an email, there are many reasons while it’s not a good idea. So whenever we are talking about creating a new email, we mean that Glue for Outlook will create a new email window and populate it, but it will not send the email automatically and will instead let the user press the Send button.
To compose a new email use the compose method of the Outlook interface.
glue.outlook().compose(message -> message
.to("test@test.com")
.cc("someone@else.com")
.subject("This is simply a test")
.body("<p>Hello from <b>Java Glue42</b></p>"));
Appendices
Appendix A: Reference Configuration
glue {
# A name that identifies the glue application instance created.
#application: ""
gateway: {
# The url to use when connecting to the gateway.
url: "ws://127.0.0.1:8385/gw"
ws: {
# The maximum message size.
max-message-size: "100 MiB"
# The maximum pool size.
# Defaults to max(3, number of available processors)
#max-pool-size:
}
}
auth: {
# The authentication provider.
# Allowed values are "" and win
provider: ""
# The authentication method.
# Allowed values are secret, access-token and gateway-token
method: secret
# Configuration for the secret method
username: ${user.name}
password: ""
# Configuration for access-token and gateway-token methods
// token: ""
}
region: "DEMO"
region: ${?GLUE-REGION}
environment: "T42"
environment: ${?GLUE-ENV}
interop: {
instance: true
}
contexts: true
windows: {
sticky-agent: ${glue.region}-${glue.environment}
}
}