Note that the following notations in the code examples below must be replaced by actual values from Franca:
// "<Attribute>" the Franca name of the attribute
// "<AttributeType>" the Franca name of the attribute type
// "<broadcast>" the Franca name of the broadcast, starting with a lowercase letter
// "<Broadcast>" the Franca name of the broadcast, starting with capital letter
// "BroadcastFilter<Attribute>" Attribute is the Franca attributes name
// "<Filter>" the Franca name of the broadcast filter
// "<interface>" the Franca interface name, starting with a lowercase letter
// "<Interface>" the Franca interface name, starting with capital letter
// "<method>" the Franca method name, starting with a lowercase letter
// "<Method>" the Franca method name, starting with capital letter
// "<OutputType>" the Franca broadcast output type name
// "<Package>" the Franca package name
// "<ProviderDomain>" the provider domain name used by provider and client
// "<ReturnType>" the Franca return type name
The Franca <Package>
will be transformed to the Javascript module joynr.<Package>
.
The Franca <TypeCollection>
will be transformed to the Javascript
module joynr.<Package>.<TypeCollection>
.
Any Franca complex type <TypeCollection>.<Type>
will result in the creation of an object
joynr.<Package>.<TypeCollection>.<Type>
(see above).
The same <Type>
will be used for all elements in the event that this type is used as an
element of other complex types, as a method input or output argument, or as a broadcast output
argument.
The Franca <Interface>
will be used as a prefix to create the following JavaScript objects:
<Interface>Provider
<Interface>Proxy
In Javascript the names of attributes, methods and broadcasts within the same interface must be unique, as each name will become a property of the Proxy object.
A Javascript joynr consumer application must "require" or otherwise load the joynr.js
module
and call its joynr.load()
method with provisioning arguments in order to create a joynr
object.
Next, for all Franca interfaces that are to be used, a proxy must be created using the
build()
method of the joynr.proxyBuilder
object, with the provider's domain passed as
an argument.
Once the proxy has been successfully created, the application can add any attribute or broadcast subscriptions it needs, and then enter its event loop where it can call the interface methods.
The following Javascript modules must be made available using require or some other loading mechanism:
// for each type <Type>
"import" js/joynr/<Package>/<Type>.js
// for each interface <Interface>
"import" js/joynr/<Package>/<Interface>Proxy.js
"import" js/joynr.js
"import" js/joynrprovisioning.common.js
"import" js/joynrprovisioning.consumer.js
The Javascript application must load and initialize the joynr runtime environment prior to calling any other Joynr API.
At the end of the application lifetime, the joynr runtime must be shutdown in order to properly deallocate resources and end any background activity.
joynr.load(provisioning).then(function(loadedJoynr) {
joynr = loadedJoynr;
// build one or more proxies and optionally set up event handlers
...
// main application code
...
// shutdown the runtime at the end of the application's lifetime
joynr.shutdown().then(function() {
...
});
}).catch(function(error) {
// error handling
});
The DiscoveryQos
configures how the search for a provider will be handled. It has the
following members:
- discoveryTimeoutMs Timeout for the discovery process (milliseconds) if no compatible provider was found within the given time. A timeout triggers a DiscoveryException or NoCompatibleProviderFoundException containing the versions of the discovered incompatible providers.
- discoveryRetryDelayMs The time to wait between discovery retries after encountering a discovery error.
- arbitrationStrategy The arbitration strategy (details see below)
- cacheMaxAgeMs Defines the maximum allowed age of cached entries (milliseconds); only younger entries will be considered. If no suitable providers are found, depending on the discoveryScope, a remote global lookup may be triggered.
- discoveryScope The discovery scope (details see below)
- providerMustSupportOnChange If set to true, select only providers which support onChange subscriptions (set by the provider in its providerQos settings)
- additionalParameters special application-specific parameters that must match, e.g. a keyword
The enumeration discoveryScope defines options to decide whether a suitable provider will be searched in the local capabilities directory or in the global one.
Available values are as follows:
- LOCAL_ONLY Only entries from local capability directory will be searched
- LOCAL_THEN_GLOBAL Entries will be taken from local capabilities directory, unless no such entries exist, in which case global entries will be considered as well.
- LOCAL_AND_GLOBAL Entries will be taken from local capabilities directory and from global capabilities directory.
- GLOBAL_ONLY Only the global entries will be looked at.
Default discovery scope: LOCAL_THEN_GLOBAL
Whenever global entries are involved, they are first searched in the local cache. In case no global entries are found in the cache, a remote lookup is triggered.
The arbitration strategy defines how the results of the scoped lookup will be sorted
and / or filtered. The arbitration strategy is a function with one parameter (the array of
capability entries found). It can either be selected from the predefined arbitration strategies
in ArbitrationStrategyCollection or provided as user-defined function. If this user-defined
function myFunction
needs additional filter criteria like the arbitration strategy Keyword,
the result of myFunction.bind(myParam)
has to be used as arbitration strategy.
Predefined arbitration strategies:
- ArbitrationStrategyCollection.LastSeen The participant that was last refreshed (i.e. with the most current last seen date) will be selected
- ArbitrationStrategyCollection.Nothing use DefaultArbitrator which picks the first discovered entry with compatible version
- ArbitrationStrategyCollection.HighestPriority Highest priority provider will be selected
- ArbitrationStrategyCollection.Keyword Only a Provider that has keyword set will be selected
Default arbitration strategy: ArbitrationStrategyCollection.LastSeen
The priority used by the arbitration strategy HighestPriority is set by the provider in its providerQos settings.
Example for setting up a DiscoveryQos
object:
// additionalParameters unclear
// there is currently no ArbitrationConstants in Javascript like in Java
// { "keyword" : "someKeyword" }
// { "fixedParticipantId" : "someParticipantId" }
// { }
var discoveryQos = new joynr.proxy.DiscoveryQos({
discoveryTimeoutMs : 30000,
discoveryRetryDelayMs : 1000,
arbitrationStrategy : joynr.types.ArbitrationStrategyCollection.LastSeen,
cacheMaxAgeMs : 0,
discoveryScope : joynr.types.DiscoveryScope.LOCAL_THEN_GLOBAL,
providerMustSupportOnChange : false,
// additional parameters are used for arbitration strategy Keyword (key: "keyword")
// or can be used for custom arbitration strategies
additionalParameters : {
"key1": "value1",
...
"keyN": "valueN"
}
});
Missing parameters will be replaced by the default settings.
The MesssagingQos
object defines the roundtrip timeout in milliseconds for
RPC requests (getter/setter/method calls) and unsubscribe requests and it allows
definition of additional custom message headers.
The ttl for subscription requests is calculated from the expiryDateMs
in the SubscriptionQos settings.
The ttl of internal joynr messages (e.g. provider discovery) can be set via the
internalMessagingQosValue in the provisioning settings
If no specific setting is given, the default roundtrip timeout is 60 seconds. The keys of custom message headers may contain ascii alphanumeric or hyphen. The values of custom message headers may contain alphanumeric, space, semi-colon, colon, comma, plus, ampersand, question mark, hyphen, dot, star, forward slash and back slash. If a key or value is invalid, the API method called to introduce the custom message header throws an Error.
Example:
var messagingQos = new joynr.messaging.MessagingQos({
ttl: 60000,
// optional custom headers
customHeaders: {
"key1": "value1",
...
"keyN": "valueN"
}
});
// optional
messagingQos.putCustomHeader("anotherKey", "anotherValue");
Proxy creation is necessary before services from a provider can be called:
- call its methods (RPC) asynchronously
- subscribe or unsubscribe to its attributes or update a subscription
- subscribe or unsubscribe to its broadcasts or update a subscription
The ProxyBuilder.build call requires the provider's domain. Optionally, messagingQos and discoveryQos settings can be specified if the default settings are not suitable.
In case no suitable provider can be found during discovery, a DiscoveryException
or
NoCompatibleProviderFoundException
is thrown.
var domain = "<ProviderDomain>";
var messagingQos, discoveryQos;
// setup messagingQos, discoveryQos
joynr.proxyBuilder.build(<Interface>Proxy, {
domain: domain,
discoveryQos: discoveryQos, // optional
messagingQos: messagingQos // optional
}).then(function(<interface>Proxy) {
// subscribe to attributes (optional)
// subscribe to broadcasts (optional)
// call methods or setup event handlers which call methods
}).catch(function(error) {
// handle error
});
In Javascript all method calls are asynchronous. Since the local proxy method returns a Promise, the reaction to the resolving or rejecting of the Promise can be immediately defined. Note that the message order on Joynr RPCs will not be preserved; if calling order is required, then the subsequent dependent call should be made in the following then() call.
<interface>Proxy.<method>(... optional arguments ...).then(function(response) {
// call successful, handle response value
}).catch(function(error) {
// call failed, execute error handling
// The following objects are used to receive error details from provider side:
// - joynr.exceptions.ApplicationException (its member 'error' holds the error enumeration value,
// wrt. error enumeration value range please refer to the Franca specification of the method)
// - joynr.exceptions.ProviderRuntimeException (with embedded 'detailMessage')
});
A subscription quality of service setting is required for subscriptions to broadcasts or attribute changes. The following sections cover the 4 quality of service objects available.
SubscriptionQos
has the following members:
- expiryDateMs Absolute Time until notifications will be send (in milliseconds)
var subscriptionQos = new joynr.proxy.SubscriptionQos({
expiryDateMs : 0,
});
The default values are as follows:
{
expiryDateMs: SubscriptionQos.NO_EXPIRY_DATE, // 0
publicationTtlMs : SubscriptionQos.DEFAULT_PUBLICATION_TTL // 10000
}
The object MulticastSubscriptionQos
inherits from SubscriptionQos
.
This object should be used for subscriptions to non-selective broadcasts.
Example:
var multicastSubscriptionQos = new joynr.proxy.MulticastSubscriptionQos({
validityMs : 3000000
});
or alternatively
var multicastSubscriptionQos = new joynr.proxy.MulticastSubscriptionQos({
expiryDateMs : Date.now() + 3000000
});
The default is as follows:
{
expiryDateMs: SubscriptionQos.NO_EXPIRY_DATE // 0
}
PeriodicSubscriptionQos
has the following additional members:
- periodMs defines how long to wait before sending an update even if the value did not change
- alertAfterIntervalMs Timeout for notifications, afterwards a missed publication notification will be sent (milliseconds)
- publicationTtlMs Lifespan of a notification (in milliseconds), the notification will be deleted afterwards The API will be changed in the future: proxy subscribe calls will no longer take a subscriptionQos; instead the publication TTL will be settable on the provider side.
This object can be used for subscriptions to attributes.
Note that updates will be sent only based on the specified interval, and not as a result of an attribute change.
var subscriptionQosPeriodic = new joynr.proxy.PeriodicSubscriptionQos({
periodMs : 60000,
alertAfterIntervalMs : 0,
publicationTtlMs : 10000
});
The default values are as follows:
{
periodMs: PeriodicSubscriptionQos.DEFAULT_PERIOD_MS, // 60000
alertAfterIntervalMs: PeriodicSubscriptionQos.NO_ALERT_AFTER_INTERVAL, // 0
publicationTtlMs : SubscriptionQos.DEFAULT_PUBLICATION_TTL // 10000
}
The object OnChangeSubscriptionQos
inherits from SubscriptionQos
and has the following
additional members:
- minIntervalMs Minimum time to wait between successive notifications (milliseconds)
- publicationTtlMs Lifespan of a notification (in milliseconds), the notification will be deleted afterwards The API will be changed in the future: proxy subscribe calls will no longer take a subscriptionQos; instead the publication TTL will be settable on the provider side.
This object should be used for subscriptions to selective broadcasts. It can also be used for subscriptions to attributes if no periodic update is required.
Example:
var subscriptionQosOnChange = new joynr.proxy.OnChangeSubscriptionQos({
minIntervalMs : 1000,
publicationTtlMs : 10000
});
The default is as follows:
{
minIntervalMs: OnChangeSubscriptionQos.DEFAULT_MIN_INTERVAL_MS, // 1000
publicationTtlMs : SubscriptionQos.DEFAULT_PUBLICATION_TTL // 10000
}
The object OnChangeWithKeepAliveSubscriptionQos
inherits from OnChangeSubscriptionQos
and has the following additional members:
- maxIntervalMs Maximum time to wait between notifications, if value has not changed
- alertAfterIntervalMs Timeout for notifications, afterwards a missed publication notification will be sent (milliseconds)
This object can be used for subscriptions to attributes. Updates will then be sent both periodically and after a change (i.e. this acts like a combination of PeriodicSubscriptionQos and OnChangeSubscriptionQos).
Using it for subscriptions to broadcasts is theoretically possible because of inheritance but makes no sense (in this case the additional members will be ignored).
Example:
var subscriptionQosOnChangeWithKeepAlive = new joynr.proxy.OnChangeWithKeepAliveSubscriptionQos({
maxIntervalMs : 60000,
alertAfterIntervalMs: 0
});
The default is as follows:
{
maxIntervalMs : OnChangeWithKeepAliveSubscriptionQos.DEFAULT_MAX_INTERVAL_MS // 60000
alertAfterIntervalMs: OnChangeWithKeepAliveSubscriptionQos.NO_ALERT_AFTER_INTERVAL // 0
}
Attribute subscription - depending on the subscription quality of service settings used - informs an application either periodically and / or on change of an attribute about the current value.
The subscriptionId is returned asynchronously after the subscription is successfully registered at the provider. It can be used later to update the subscription or to unsubscribe from it. If the subscription failed, a SubscriptionException will be returned via the callback (onError) and via the Promise.
To receive the subscription, callback functions (onReceive, onSubscribed, onError) have to be provided as outlined below.
<interface>Proxy.<Attribute>.subscribe({
subscriptionQos : subscriptionQosOnChange,
// Gets called on every received publication
onReceive : function(value) {
// handle subscription publication
},
// Gets called when the subscription is successfully registered at the provider
onSubscribed : function(subscriptionId) { // optional
// save the subscriptionId for updating the subscription or unsubscribing from it
// the subscriptionId can also be taken from the Promise returned by the subscribe call
},
// Gets called on every error that is detected on the subscription
onError: function(error) {
// handle subscription error, e.g.:
// - SubscriptionException if the subscription registration failed at the provider
// - PublicationMissedException if a periodic subscription publication does not arrive in time
}
}).then(function(subscriptionId) {
// subscription successful, store subscriptionId for later use
}).catch(function(error) {
// handle error case
});
The subscribe()
method can also be used to update an existing subscription, by passing the
subscriptionId as an additional parameter as follows:
// subscriptionId from earlier subscribe call
<interface>Proxy.<Attribute>.subscribe({
subscriptionQos : subscriptionQosOnChange,
subscriptionId: subscriptionId,
// Gets called on every received publication
onReceive : function(value) {
// handle subscription publication
},
// Gets called when the subscription is successfully updated at the provider
onSubscribed : function(subscriptionId) { // optional
// save the subscriptionId for updating the subscription or unsubscribing from it
// the subscriptionId can also be taken from the Promise returned by the subscribe call
},
// Gets called on every error that is detected on the subscription
onError: function(error) {
// handle subscription error, e.g.:
// - SubscriptionException if the subscription registration failed at the provider
// - PublicationMissedException if a periodic subscription publication does not arrive in time
}
}).then(function(subscriptionId) {
// subscription update successful, the subscriptionId should be the same as before
}).catch(function(error) {
// handle error case
});
Unsubscribing from an attribute subscription requires the subscriptionId returned by the earlier subscribe call.
<interface>Proxy.<Attribute>.unsubscribe({
subscriptionId: subscriptionId
}).then(function() {
// handle success case
}).catch(function(error) {
// handle error case
});
A Broadcast subscription informs the application in case a broadcast is fired by a provider. The output values are returned via a callback function.
A broadcast is selective only if it is declared with the selective
keyword in Franca, otherwise it
is non-selective.
Non-selective broadcast subscriptions can be passed optional partitions. A partition is a hierarchical list of strings similar to a URL path. Subscribing to a partition will cause only those broadcasts to be sent to the consumer that match the partition. Note that the partition is set when subscribing on the consumer side, and must match the partition set on the provider side when the broadcast is performed.
Example: a consumer could set a partition of "europe", "germany", "munich" to receive broadcasts for Munich only. The matching provider would use the same partition when sending the broadcast.
The subscriptionId is returned asynchronously after the subscription is successfully registered at the provider. It can be used later to update the subscription or to unsubscribe from it. If the subscription failed, a SubscriptionException will be returned via the callback (onError) and via the Promise.
To receive the subscription, callback functions (onReceive, onSubscribed, onError) have to be provided as outlined below.
<interface>Proxy.<Broadcast>.subscribe({
subscriptionQos : multicastSubscriptionQos,
// Gets called on every received publication
onReceive : function(value) {
// handle subscription publication
},
// Gets called when the subscription is successfully registered at the provider
onSubscribed : function(subscriptionId) { // optional
// save the subscriptionId for updating the subscription or unsubscribing from it
// the subscriptionId can also be taken from the Promise returned by the subscribe call
},
// Gets called on every error that is detected on the subscription
onError: function(error) {
// handle subscription error, e.g.:
// - SubscriptionException if the subscription registration failed at the provider
// - PublicationMissedException if a periodic subscription publication does not arrive in time
}
// optional parameter for multicast subscriptions (subscriptions to non-selective broadcasts)
partitions: [partitionLevel1,
...
partitionLevelN]
}).then(function(subscriptionId) {
// subscription successful, store subscriptionId for later use
}).catch(function(error) {
// handle error case
});
The partition syntax is explained in the multicast concept
The subscribe()
method can also be used to update an existing subscription, when the
subscriptionId is passed as an additional parameter as follows:
<interface>Proxy.<Broadcast>.subscribe({
subscriptionQos : multicastSubscriptionQos,
subscriptionId: subscriptionId,
// Gets called on every received publication
onReceive : function(value) {
// handle subscription publication
},
// Gets called when the subscription is successfully updated at the provider
onSubscribed : function(subscriptionId) { // optional
// save the subscriptionId for updating the subscription or unsubscribing from it
// the subscriptionId can also be taken from the Promise returned by the subscribe call
},
// Gets called on every error that is detected on the subscription
onError: function(error) {
// handle subscription error, e.g.:
// - SubscriptionException if the subscription registration failed at the provider
// - PublicationMissedException if a periodic subscription publication does not arrive in time
}
// optional parameter for multicast subscriptions (subscriptions to non-selective broadcasts)
partitions: [partitionLevel1,
...
partitionLevelN]
}).then(function(subscriptionId) {
// subscription update successful, the subscriptionId should be the same as before
}).catch(function(error) {
// handle error case
});
Broadcast subscription with a filter informs the application in case a selective broadcast which matches filter criteria is fired from the provider side. The output values are returned via callback.
The subscriptionId is returned asynchronously after the subscription is successfully registered at the provider. It can be used later to update the subscription or to unsubscribe from it. If the subscription failed, a SubscriptionException will be returned via the callback (onError) and via the Promise.
To receive the subscription, callback functions (onReceive, onSubscribed, onError) have to be provided as outlined below.
In addition to the normal broadcast subscription, the filter parameters for this broadcast must be
created and initialized as additional parameters to the subscribe
method. These filter
parameters are used to receive only those broadcasts matching the provided filter criteria.
var fParam = <interface>Proxy.<broadcast>.createFilterParameters();
// for each parameter
fParam.set<Parameter>(parameterValue);
<interface>Proxy.<Broadcast>.subscribe({
subscriptionQos : subscriptionQosOnChange,
filterParameters : fParam,
// Gets called on every received publication
onReceive : function(value) {
// handle subscription publication
},
// Gets called when the subscription is successfully registered at the provider
onSubscribed : function(subscriptionId) { // optional
// save the subscriptionId for updating the subscription or unsubscribing from it
// the subscriptionId can also be taken from the Promise returned by the subscribe call
},
// Gets called on every error that is detected on the subscription
onError: function(error) {
// handle subscription error, e.g.:
// - SubscriptionException if the subscription registration failed at the provider
// - PublicationMissedException if a periodic subscription publication does not arrive in time
}
}).then(function(subscriptionId) {
// subscription successful, store subscriptionId for later use
}).catch(function(error) {
// handle error case
});
The subscribeTo method can also be used to update an existing subscription, by passing the subscriptionId as an additional parameter as follows:
var fParam = <interface>Proxy.<broadcast>.createFilterParameters();
// for each parameter
fParam.set<Parameter>(parameterValue);
<interface>Proxy.<Broadcast>.subscribe({
subscriptionQos : subscriptionQosOnChange,
subscriptionId: subscriptionId,
filterParameters : fParam,
// Gets called on every received publication
onReceive : function(value) {
// handle subscription publication
},
// Gets called when the subscription is successfully updated at the provider
onSubscribed : function(subscriptionId) { // optional
// save the subscriptionId for updating the subscription or unsubscribing from it
// the subscriptionId can also be taken from the Promise returned by the subscribe call
},
// Gets called on every error that is detected on the subscription
onError: function(error) {
// handle subscription error, e.g.:
// - SubscriptionException if the subscription registration failed at the provider
// - PublicationMissedException if a periodic subscription publication does not arrive in time
}
}).then(function(subscriptionId) {
// subscription update successful, the subscriptionId should be the same as before
}).catch(function(error) {
// handle error case
});
Unsubscribing from a broadcast subscription requires the subscriptionId returned asynchronously by the earlier subscribe call.
<interface>Proxy.<Broadcast>.unsubscribe({
subscriptionId : subscriptionId,
}).then(function() {
// call successful
}).catch(function(error) {
// handle error case
});
A Javascript joynr provider application must "require" or otherwise load the joynr.js
module and call its joynr.load()
method with provisioning arguments in order to create a
joynr object.
Next, for all Franca interfaces that are being implemented, a providerBuilder must be created
using the build()
method of the joynr.providerBuilder
object supplying the providers
domain as argument.
Upon successful creation, the application can register all Capabilities it provides, and enter its event loop where it can handle calls from the proxy side.
The following Javascript modules must be made "required" or otherwise loaded:
// for each type <Type>
"import" js/joynr/<Package>/<Type>.js
// for each interface <Interface>
"import" js/joynr/<Package>/<Interface>Proxy.js
"import" js/joynr.js
"import" js/joynrprovisioning.common.js
"import" js/joynrprovisioning.provider.js
The ProviderQos
has the following members:
- customParameters e.g. the key-value for the arbitration strategy Keyword during discovery
- priority the priority used for arbitration strategy HighestPriority during discovery
- scope the scope (see below), used in discovery
- supportsOnChangeSubscriptions whether the provider supports subscriptions on changes
The scope can be
- LOCAL The provider will be registered in the local capability directory
- GLOBAL The provider will be registered in the local and global capability directory
Example:
var providerQos = new joynr.types.ProviderQos({
customParameters: [],
priority : 100,
scope: joynr.types.ProviderScope.GLOBAL,
supportsOnChangeSubscriptions : true
});
A provider application must load joynr and when this has been successfully finished, it can register a Provider implementation for each Franca interface it implements. It is also possible to unregister that implementation again, e.g. on shutdown.
While the implementation is registered, the provider will respond to any method calls from outside, can report any value changes via publications to subscribed consumers, and may fire broadcasts, as defined in the Franca interface.
At the end of the application lifetime, the joynr runtime must be shutdown in order to properly deallocate resources and end any background activity.
$(function() {
// for each <Interface> where a Provider should be registered for later
var <interface>provider = null;
var <interface>ProviderImpl = new <Interface>ProviderImpl();
var provisioning = {};
provisioning.channelId = "someChannel";
joynr.load(provisioning).then(function(loadedJoynr) {
joynr = loadedJoynr;
// when applications starts up:
// register <Interface>provider
...
// main loop here
...
// when application ends:
// unregister <Interface>provider
...
// shutdown the joynr runtime
joynr.shutdown().then(function() {
...
});
}).catch(function(error){
if (error) {
throw error;
}
});
})();
When registering a provider implementation for a specific Franca interface, the object implementing the interface, the provider's domain and the provider's quality of service settings are passed as parameters.
var <interface>ProviderQos;
<interface>Provider = joynr.providerBuilder.build(<Interface>Provider, <interface>ProviderImpl);
// for any filter of a broadcast with filter
<interface>Provider.<broadcast>.addBroadcastFilter(new <Filter>BroadcastFilter());
// setup <interface>ProviderQos
joynr.registration.registerProvider(
domain,
<interface>Provider,
<interface>ProviderQos
).then(function() {
// registration successful
}).catch(function() {
// registration failed
});
Unregistering a previously registered provider requires the provider's domain and the object that represents the provider implementation.
// provider should have been set and registered previously
joynr.registration.unregisterProvider(
domain,
<Interface>provider
).then(function() {
// unregistration successful
}).catch(function() {
// unregistration failed
});
The function implementing the interface must provide code for all its methods and a getter function for every attribute.
var <Interface>ProviderImpl =
function <Interface>ProviderImpl() {
var self = this;
// define <method> handler
// define internal representation of <attribute> and
// getter handlers per <attribute>
// wrappers to fire broadcasts
};
Each handler for a Franca method for a specific interface is implemented as a function object member of this. The parameters are provided as objects. The implementation can be done either asynchronously or synchronously.
this.<method> = function(parameters) {
// handle method, return returnValue of type <returnType> with
// return returnValue;
// - or -
// throw errorEnumerationValue;
// (wrt. error enumeration value range please refer to the Franca specification of the method)
// - or -
// throw new joynr.exceptions.ProviderRuntimeException({ detailMessage: "reason" });
};
this.<method> = function(parameters) {
var result = new Promise(function(resolve, reject) {
// handle method, then either return the value
// of type <returnType> with
// resolve(returnValue);
// - or -
// reject(errorEnumerationValue);
// (wrt. error enumeration value range please refer to the Franca specification of the method)
// - or -
// reject(new ProviderRuntimeException({ detailMessage: "reason" }));
});
// handle method, return returnValue of type <returnType>
return result;
};
For each Franca attribute of an interface, a member of this named after the
<attribute>
has to be created which consists of an object which includes a getter function
as attribute that returns the current value of the <attribute>
. Also an internal
representation of the Franca attribute value has to be created and properly intialized.
// for each <attribute> of the <interface> provide an internal representation
// and a getter
var internal<Attribute> = <initialValue>;
this.<attribute> = {
get: function() {
return attributeValue;
}
};
The provider implementation must inform about any change of an attribute which is not done via a remote setter call by calling valueChanged on the given attribute. If an attribute setter is called remotely, an attribute change publication will be triggered automatically.
self.<attribute>.valueChanged(newValue);
For each Franca broadcast, a member of this named after the <broadcast>
has to be created which consists of an empty object.
this.<broadcast> = {};
The broadcast can then later be fired using
this.fire<Broadcast> = function() {
var outputParameters;
outputParameters = self.<broadcast>.createBroadcastOutputParameters();
// foreach output parameter of the broadcast
outputParameters.set<Parameter>(value);
// optional: the partitions to be used for the broadcast
// Note: wildcards are only allowed on consumer side
var partitions = [partitionLevel1,
...
partitionLevelN];
self.<broadcast>.fire(outputParameters[, partitions]);
}
The partition syntax is explained in the multicast concept
In contrast to unfiltered broadcasts, to realize selective (filtered) broadcasts, the filter logic has to be implemented and registered by the provider. If multiple filters are registered on the same provider and broadcast, all filters are applied in a chain and the broadcast is only delivered if all filters in the chain return true.
A broadcast filter object implements a filtering function called filter()
which returns a
boolean value indicating whether the broadcast should be delivered. The input parameters of the
filter()
method consist of the output parameters of the broadcast and the filter parameters
used by the consumer on subscription.
(function(undefined) {
var <Filter>BroadcastFilter = function <Filter>BroadcastFilter() {
if (!(this instanceof <Filter>BroadcastFilter)) {
return new <Filter>BroadcastFilter();
}
Object.defineProperty(this, 'filter', {
enumerable: false,
value: function(broadcastOutputParameters, filterParameters) {
// Parameter value can be evaluated by calling getter functions, e.g.
// broadcastOutputParameters.get<OutputParameter>()
// filterParameters can be evaluated by using properties, e.g.
// filterParameters.<property>
//
// Evaluate whether the broadcastOutputParameters fulfill
// the filterParameter here, then return true, if this is
// the case and the publication should be done, false
// otherwise.
return <booleanValue>;
};
});
};
return <Filter>BroadcastFilter;
}());