Interface DataSessionInterface

The DataSessionInterface is the formalization of the connection between a 3djuump Infinite proxy and the client.

The DataSessionInterface is created from a connected DirectorySessionInterface and a proxy by the use of the DirectorySessionInterface.createDataSession function.

The open data session procedure is detailed below :

open data session sequence
The DataSession can only be opened once, when closed, there is no way to reuse this object. You will have to call again the DirectorySessionInterface.createDataSession function.
/** 
* Sample to illustrate the use of the open data session procedure with the DataSessionInterface.
*/
import { DataSessionInterface, DataSessionInterfaceSignal, DirectorySessionInterface, InfiniteCacheInterface, tListenerCallback } from 'generated_files/documentation/appinfiniteapi';

// callbacks called when IdleDataSession, DataSessionClosed, DMULoadingSuccess and DMULoadingFailed events are triggered
let onInactivityDetection : tListenerCallback;
let onCloseDBSuccess : tListenerCallback;
let onDMULoaded : tListenerCallback;
let onOpenDBFailed : tListenerCallback;

// the id of the build to open (retrieved previously)
let sBuildId : string;
// the optional cache (may be created previously)
let lCache : InfiniteCacheInterface | undefined;
// the directory session should have been created previously
let lDirectorySession : DirectorySessionInterface;

const lDataSession : DataSessionInterface | undefined = lDirectorySession.createDataSession(sBuildId, lCache);
// open the database
if (lDataSession)
{
// do something with your GUI
// ...
// when the data session is closed due to inactivity
lDataSession.addEventListener(DataSessionInterfaceSignal.IdleDataSession, onInactivityDetection);
// when the data session is closed
lDataSession.addEventListener(DataSessionInterfaceSignal.DataSessionClosed, onCloseDBSuccess);
// when the data session has retrieved all required data
lDataSession.addEventListener(DataSessionInterfaceSignal.DMULoadingSuccess, onDMULoaded);
// if unfortunately something went wrong with the loading
lDataSession.addEventListener(DataSessionInterfaceSignal.DMULoadingFailed, onOpenDBFailed);
// and trigger the data session loading
lDataSession.openDataSession();
}

Connecting a DataSessionInterface to an InfiniteEngineInterface.

The DataSessionInterface may be linked with an InfiniteEngineInterface to render the content of the DMU. Please use bindInfiniteEngine, or InfiniteEngineInterface.bindDataSession.

Tags System.

There exists two types of tags :

  • open tags that allow a user to open a Build.
  • extra tags inside a Build that allows multiple security levels inside a given build, these tags may decorate individual documents and 3D data inside a Build, adding increased security to these documents.

Each user is assigned a set of tags (UserData.viewtags inside a ConnectionData), that may be :

  • individually set for this user.
  • inherited from the user team tags.
  • inherited from the web application being run at the moment.
  • other sources.

A user is allowed to open a build if its full list of the Build open tags are contained inside the Build.

NB: If a build is contained inside the ConnectionData, then the user has the required tags (Build.tags are only informational).

Intersecting the Build.extratags and UserData.viewtags tells the extra tags that may be used to see security protected data. These tags may be used to open a Build with fewer security levels, with openDataSession. Passing undefined with openDataSession means opening the Build with the full set of allowed view tags of the User. You may query the list of extra tags that have been granted with getGrantedSecurityTags once the data session is connected.

Added functionalities.

The data session may be open with added functionalities (scopes). When opening a data session, the user may request the rights to :

  • Download evojuump files.
  • Export 2d files.
  • Export 3d files.

These rights are represented by DataSessionInterfaceScopes, when using openDataSession.

Idle System.

In order to save resources on the proxy, the api features an automatic data session closing mechanism when the user is not interacting with the application. The DataSessionInterface will be closed if DataSessionInterface.restartIdleTimer is not called on user interactions.

It is composed of three pseudo-states :

  • Normal : the user is interacting regularly with the system.
  • Warning : the user has not interacted with the system from some time (2/3 of the idle duration as configured in the architecture).
  • Idle : the server resources have been cleaned up, the session is closed with no possibility to resume or recover. This state happens after the "warning" state.
idle system
The idle system.
/** 
* Sample to illustrate the binding of events to avoid being idle and disconnected.
*/
import { DataSessionInterface } from 'generated_files/documentation/appinfiniteapi';

// the DataSessionInterface has been created previously and is connected
let lDataSession: DataSessionInterface | undefined;

// restart the timer on user interactions
const cActiveCallback = (_event: Event): void => {
if (lDataSession && lDataSession.isConnected())
{
lDataSession.restartIdleTimer();
}
};

// and bind to specific event
// you may choose your own callbacks
document.addEventListener('keydown', cActiveCallback);
document.addEventListener('mousedown', cActiveCallback);
document.addEventListener('mousemove', cActiveCallback);
document.addEventListener('wheel', cActiveCallback);
document.addEventListener('contextmenu', cActiveCallback);
document.addEventListener('touchstart', cActiveCallback);
document.addEventListener('touchmove', cActiveCallback);
document.addEventListener('touchend', cActiveCallback);

Please see DirectorySessionInterface for more explanations about sessions.

All metadata filters, search procedure, data retrieval procedures are created from this interface.

The DataSessionInterface, once successfully connected to a 3djuump Infinite build (see DataSessionInterfaceSignal.DMULoadingSuccess) provides access to

Id converters and data retrieval interfaces are somewhat autonomous. They only rely on a WorkingSetInterface to be used.

However, filtering interfaces are linked together, making difficult to find the correct order to update them and when. For these reasons, and to avoid too many requests being sent to the 3djuump Infinite server, the update is triggered by the DataSessionInterface that handles the dependency graph of all these items, and updates only the required interfaces with update.

All these interfaces (filtering, id conversion, data retrieval) work asynchronously : they all feature some kind of "ready" signal telling the result is available, just call EventDispatcherInterface.addEventListener with the correct signal on the required interfaces.

These interfaces has a InfiniteObjectInterface.dispose function to get rid of them. Do not forget to call these functions to save memory and CPU usage.

The only way to create sets of part instances is to use a WorkingSetInterface that allows computing the result of the intersection of filtering queries with some Infinite configurations (see ConfigurationInterface, WorkingSetInterface) and optionally other WorkingSetInterface(s). Available configurations (created by the 3djuump Infinite maintainer) are accessed through getConfigurationList, they are then "included" by id in a WorkingSetInterface.

DMU statistics (Axis Aligned Bounding Box (AABB) of each geometric instance, diagonal length of each geometric instance, min/max of diagonal length, DMU AABB, DMU Unit, maximum geometric instance id, maximum part instance id) and the metadata dictionary (AttributesDictionaryInterface) are accessed through the DataSessionInterface.

/** 
* Sample to illustrate the use of multiple WorkingSetInterfaces to define a set of visible pieces, and
* colorize a subset.
* The visibility is composed of all the part instances included in a Box, that have the "CompletionStatus" attribute
* set to "done".
* The colorization set is based on the visibility, the part instances that have the attribute "ToBeRedesigned"
* true should be colored in yellow.
* This colors all part instance in yellow in the given box, that ave the attribute "ToBeRedesigned"
* true and "CompletionStatus" attribute set to "done".
* This sample uses multiple WorkingSetInterface.
* It uses some FilterAABBInterface, FilterAttributeInterface, FilterBooleanInterface.
*/
import {
AttributesDictionaryInterface, AttributeInfoInterface, AttributeType, DataSessionInterface,
InfiniteEngineInterface, Vector3, AABB, FilterAABBInterface, FilterAttributeInterface,
GroupOperator, VisualStates, FilterBooleanInterface, WorkingSetInterface, WorkingSetInterfaceSignal,
WorkingSetDataRetrieval,
WorkingSetBehavior
} from 'generated_files/documentation/appinfiniteapi';

// lEngineInterface has been created previously
let lEngineInterface : InfiniteEngineInterface;
// the DataSessionInterface has been created previously, is connected and is bound to the Infinite engine
let lDataSession : DataSessionInterface;

// MAKE SURE the attributes "CompletionStatus", "ToBeRedesigned" are relevant
const lAttributeDictionary : AttributesDictionaryInterface = lDataSession.getAttributesDictionary();
let lAttributeInfo : AttributeInfoInterface | undefined = lAttributeDictionary.getAttributeInfo('CompletionStatus');
// make sure the attribute is a string one
console.assert((lAttributeInfo !== undefined) && (lAttributeInfo.getAttributeType() === AttributeType.ATTR_STRING));

lAttributeInfo = lAttributeDictionary.getAttributeInfo('ToBeRedesigned');
// make sure the attribute is a date one
console.assert((lAttributeInfo !== undefined) && (lAttributeInfo.getAttributeType() === AttributeType.ATTR_BOOLEAN));

// create a custom material yellow
const lMaterialId : number = lEngineInterface.getMaterialManager().createNewMaterial(new Vector3(1, 1, 0));
// create a a working set that contain the configurations
// we want to get geometric instances result
// if nothing is set, this working set should include all parts ('unconfigured')
const lConfContext : WorkingSetInterface = lDataSession.createWorkingSet(
// we may retrieve the geometric instances
WorkingSetDataRetrieval.R_OnlyGeometricInstances,
// This working set should discard empty sets if no
// configurations, no filters, and no dependencies
WorkingSetBehavior.B_DiscardConfigurationsIfEmptyBit | WorkingSetBehavior.B_DiscardFiltersIfEmptyBit | WorkingSetBehavior.B_DiscardDependenciesIfEmptyBit
);

// no configuration for the moment (all `part instances`)
// lConfContext holds all geometric instance ids
lConfContext.setActiveConfs([]);

// the AABB to use
const lABB : AABB = new AABB();
lABB.mCenter.x = 3;
lABB.mCenter.y = 3;
lABB.mCenter.z = 3;

lABB.mHalfExtent.x = 10;
lABB.mHalfExtent.y = 10;
lABB.mHalfExtent.z = 10;

// create the visibility Working set
// we want to get geometric instances result
const lVisibilityFilterSolver : WorkingSetInterface = lDataSession.createWorkingSet(
WorkingSetDataRetrieval.R_OnlyGeometricInstances,
WorkingSetBehavior.B_DiscardConfigurationsIfEmptyBit
);

// create the inner Working set
const lInnerWorkingSet : WorkingSetInterface = lDataSession.createWorkingSet(
WorkingSetDataRetrieval.R_Nothing,
WorkingSetBehavior.B_DiscardConfigurationsIfEmptyBit | WorkingSetBehavior.B_DiscardFiltersIfEmptyBit
);
lInnerWorkingSet.insertWorkingSetDependency(0, lConfContext, GroupOperator.GO_INTERSECTION);
lVisibilityFilterSolver.insertWorkingSetDependency(0, lInnerWorkingSet, GroupOperator.GO_UNION);

// create a box filter
const lFilterAABB : FilterAABBInterface = lDataSession.createFilterAABB();
// useless, GroupOperator.GO_UNION is the default operator when creating a new filter
// lFilterAABB.setFilterOperator(GroupOperator.GO_UNION);
lFilterAABB.setAABB(lABB);

// create a FilterAttributeInterface
const lFilterAttributes : FilterAttributeInterface = lDataSession.createFilterAttribute();
// completion status to done
lFilterAttributes.setAttributeName('CompletionStatus');
lFilterAttributes.setExactValues(['done']);
// no n/a
lFilterAttributes.setNaValueChecked(false);

// intersection is the way to go since intersection of box and instances that have the field "CompletionStatus"
// to "done"
// only change the operator of the filters except the first
lFilterAttributes.setFilterOperator(GroupOperator.GO_INTERSECTION);

// and add the filters
// push back (-1) the AABB filter
lVisibilityFilterSolver.insertFilter(-1, lFilterAABB);
// push back (-1) the FilterAttributeInterface, as it is the second one, its operator is used and therefore
// intersection is used
lVisibilityFilterSolver.insertFilter(-1, lFilterAttributes);

lVisibilityFilterSolver.addEventListener(WorkingSetInterfaceSignal.WorkingSetReady, () =>
{
const lGeometries : Uint32Array | undefined = lVisibilityFilterSolver.getGeometricInstanceIds();
if (lGeometries)
{
// set hidden and not ghosted for everyone
lEngineInterface.updateGeometricStateForAll(VisualStates.S_Ghost | VisualStates.S_Hidden, (~VisualStates.S_Ghost) | VisualStates.S_Hidden);
// and set not hidden for the given geometries
lEngineInterface.updateGeometricState(lGeometries, VisualStates.S_Hidden, ~VisualStates.S_Hidden);
}
});

// create the colorize Working Set
// we want to get geometric instances result
const lColorizeFilterSolver : WorkingSetInterface = lDataSession.createWorkingSet(
WorkingSetDataRetrieval.R_OnlyGeometricInstances,
WorkingSetBehavior.B_DiscardConfigurationsIfEmptyBit
);
// create an attribute filter
const lColorizeFilterAttributes : FilterBooleanInterface = lDataSession.createFilterBoolean();
// search ToBeRedesigned attribute
lColorizeFilterAttributes.setAttributeName('ToBeRedesigned');
// value should be true
lColorizeFilterAttributes.setBooleanValue(true);

// when the WorkingSetInterface is ready, colorize the given `geometric instances`
lColorizeFilterSolver.addEventListener(WorkingSetInterfaceSignal.WorkingSetReady, () =>
{
const lGeomIds : Uint32Array | undefined = lColorizeFilterSolver.getGeometricInstanceIds();
if (lGeomIds)
{
// change material for these elements
lEngineInterface.getMaterialManager().changeMaterialOfInstances(lGeomIds, lMaterialId);
}
});

// set the Working set of the given `part instances` list
lColorizeFilterSolver.insertWorkingSetDependency(0, lVisibilityFilterSolver, GroupOperator.GO_UNION);
// add the colorize filter
lColorizeFilterSolver.insertFilter(-1, lColorizeFilterAttributes);
// and tell the DataSessionInterface to update the modified WorkingSetInterfaces
lDataSession.update();
// theWorking set may then be used to restrict a search, or a metadata retrieval to the given Working set.

or asynchronously :
/** 
* Sample to illustrate the asynchronous use of multiple WorkingSetInterfaces to define a set of visible pieces, and
* colorize a subset.
* The visibility is composed of all the part instances included in a Box, that have the "CompletionStatus" attribute
* set to "done".
* The colorization set is based on the visibility, the part instances that have the attribute "ToBeRedesigned"
* true should be colored in yellow.
* This colors all part instance in yellow in the given box, that ave the attribute "ToBeRedesigned"
* true and "CompletionStatus" attribute set to "done".
* This sample uses multiple WorkingSetInterface.
* It uses some FilterAABBInterface, FilterAttributeInterface, FilterBooleanInterface.
*/
import {
AttributesDictionaryInterface, AttributeInfoInterface, AttributeType, DataSessionInterface,
InfiniteEngineInterface, WorkingSetInterface, Vector3, AABB,
FilterAABBInterface, FilterAttributeInterface, GroupOperator, VisualStates, FilterBooleanInterface,
AsyncUInt32ArrayResult, WorkingSetDataRetrieval, WorkingSetBehavior
} from 'generated_files/documentation/appinfiniteapi';

// lEngineInterface has been created previously
let lEngineInterface : InfiniteEngineInterface;
// the DataSessionInterface has been created previously, is connected and is bound to the Infinite engine
let lDataSession : DataSessionInterface;

// MAKE SURE the attributes "CompletionStatus", "ToBeRedesigned" are relevant
const lAttributeDictionary : AttributesDictionaryInterface = lDataSession.getAttributesDictionary();
let lAttributeInfo : AttributeInfoInterface | undefined = lAttributeDictionary.getAttributeInfo('CompletionStatus');
// make sure the attribute is a string one
console.assert((lAttributeInfo !== undefined) && (lAttributeInfo.getAttributeType() === AttributeType.ATTR_STRING));

lAttributeInfo = lAttributeDictionary.getAttributeInfo('ToBeRedesigned');
// make sure the attribute is a date one
console.assert((lAttributeInfo !== undefined) && (lAttributeInfo.getAttributeType() === AttributeType.ATTR_BOOLEAN));

// create a custom material yellow
const lMaterialId : number = lEngineInterface.getMaterialManager().createNewMaterial(new Vector3(1, 1, 0));
// create a a working set that contain the configurations
// we want to get geometric instances result
// if nothing is set, this working set should include all parts ('unconfigured')
const lConfContext : WorkingSetInterface = lDataSession.createWorkingSet(
// we may retrieve the geometric instances
WorkingSetDataRetrieval.R_OnlyGeometricInstances,
// This working set should discard empty sets if no
// configurations, no filters, and no dependencies
WorkingSetBehavior.B_DiscardConfigurationsIfEmptyBit | WorkingSetBehavior.B_DiscardFiltersIfEmptyBit | WorkingSetBehavior.B_DiscardDependenciesIfEmptyBit
);

// no configuration for the moment (all `part instances`)
// lConfContext holds all geometric instance ids
lConfContext.setActiveConfs([]);

// the AABB to use
const lABB : AABB = new AABB();
lABB.mCenter.x = 3;
lABB.mCenter.y = 3;
lABB.mCenter.z = 3;

lABB.mHalfExtent.x = 10;
lABB.mHalfExtent.y = 10;
lABB.mHalfExtent.z = 10;

// create the visibility Working set
// we want to get geometric instances result
const lVisibilityFilterSolver : WorkingSetInterface = lDataSession.createWorkingSet(
WorkingSetDataRetrieval.R_OnlyGeometricInstances,
WorkingSetBehavior.B_DiscardConfigurationsIfEmptyBit
);

// create the inner Working Set
const lInnerWorkingSet : WorkingSetInterface = lDataSession.createWorkingSet(
WorkingSetDataRetrieval.R_Nothing,
WorkingSetBehavior.B_DiscardConfigurationsIfEmptyBit | WorkingSetBehavior.B_DiscardFiltersIfEmptyBit
);
lInnerWorkingSet.insertWorkingSetDependency(0, lConfContext, GroupOperator.GO_INTERSECTION);
lVisibilityFilterSolver.insertWorkingSetDependency(0, lInnerWorkingSet, GroupOperator.GO_UNION);

// create a box filter
const lFilterAABB : FilterAABBInterface = lDataSession.createFilterAABB();
// useless, GroupOperator.GO_UNION is the default operator when creating a new filter
// lFilterAABB.setFilterOperator(GroupOperator.GO_UNION);
lFilterAABB.setAABB(lABB);

// create a FilterAttributeInterface
const lFilterAttributes : FilterAttributeInterface = lDataSession.createFilterAttribute();
// completion status to done
lFilterAttributes.setAttributeName('CompletionStatus');
lFilterAttributes.setExactValues(['done']);
// no n/a
lFilterAttributes.setNaValueChecked(false);

// intersection is the way to go since intersection of box and instances that have the field "CompletionStatus"
// to "done"
// only change the operator of the filters except the first
lFilterAttributes.setFilterOperator(GroupOperator.GO_INTERSECTION);

// and add the filters
// push back (-1) the AABB filter
lVisibilityFilterSolver.insertFilter(-1, lFilterAABB);
// push back (-1) the FilterAttributeInterface, as it is the second one, its operator is used and therefore
// intersection is used
lVisibilityFilterSolver.insertFilter(-1, lFilterAttributes);

// create the colorize Working Set
// we want to get geometric instances result
const lColorizeFilterSolver : WorkingSetInterface = lDataSession.createWorkingSet(
WorkingSetDataRetrieval.R_OnlyGeometricInstances,
WorkingSetBehavior.B_DiscardConfigurationsIfEmptyBit
);
// create an attribute filter
const lColorizeFilterAttributes : FilterBooleanInterface = lDataSession.createFilterBoolean();
// search ToBeRedesigned attribute
lColorizeFilterAttributes.setAttributeName('ToBeRedesigned');
// value should be true
lColorizeFilterAttributes.setBooleanValue(true);

// set the Working Set of the given `part instances` list
lColorizeFilterSolver.insertWorkingSetDependency(0, lVisibilityFilterSolver, GroupOperator.GO_UNION);
// add the colorize filter
lColorizeFilterSolver.insertFilter(-1, lColorizeFilterAttributes);

// the Working Set may then be used to restrict a search, or a metadata retrieval to the given Working Set.

const waitForResult = async () : Promise<void> =>
{
// and tell the DataSessionInterface to update the modified WorkingSetInterfaces (true)
const lVisibleResult : AsyncUInt32ArrayResult = await lVisibilityFilterSolver.asyncGetGeometricInstanceIds(true);
// no need to call DataSessionInterface update again (false)
const lColorizeResult : AsyncUInt32ArrayResult = await lColorizeFilterSolver.asyncGetGeometricInstanceIds(false);

if (lVisibleResult.value)
{
// set hidden and not ghosted for everyone
lEngineInterface.updateGeometricStateForAll(VisualStates.S_Ghost | VisualStates.S_Hidden, (~VisualStates.S_Ghost) | VisualStates.S_Hidden);
// and set not hidden for the given geometries
lEngineInterface.updateGeometricState(lVisibleResult.value, VisualStates.S_Hidden, ~VisualStates.S_Hidden);
}
if (lColorizeResult.value)
{
// change material for these elements
lEngineInterface.getMaterialManager().changeMaterialOfInstances(lColorizeResult.value, lMaterialId);
}
};
waitForResult();

The DataSessionInterface may be bound to an InfiniteEngineInterface in order to provide a rendering of the DMU.

Primary / Secondary session mechanism.

The same DataSessionInterface may be shared upon multiple tabs. In order to do so, one DataSessionInterface plays the role of the 'primary' session while others play the role of secondary sessions. A secondary DirectorySessionInterface must be created and opened with DirectorySessionInterface.openSecondaryDirectorySession, and a new DataSessionInterface must be created from the secondary DirectorySessionInterface. The secondary DataSessionInterface must be opened with openSecondaryDataSession, and regularly updated with setTokenValues when the primary DataSessionInterface triggers a DataSessionInterfaceSignal.TokenUpdated (and bearers are retrieved with getDataSessionBearer, and getExtendedDataSessionBearer).

/** 
* Sample to illustrate the use of the primary/secondary session mechanism of DirectorySessionInterface and DataSessionInterface.
*/
import {
InfiniteCacheFactory, DirectorySessionFactory,
InfiniteCacheInterface, DirectorySessionInterface,
DataSessionInterface,
DataSessionInterfaceSignal, DirectorySessionInterfaceSignal,
SecondaryDirectorySessionInterfaceInfo,
SecondaryDataSessionInterfaceInfo,
AuthenticationGetURLResult,
} from 'generated_files/documentation/appinfiniteapi';

// this sample holds the code to be use in the primary tab (primaryCode)
// and in the secondary tab (secondaryCode)

// a callback to receive messages
type tMessageHandler = (pMessage: any) => void;

// we suppose that there exists a message system
let sendMessage : (pMessage: any) => void;

// we suppose that we can register a handler to receive messages
let registerMessageHandler : (pMessageHandler: tMessageHandler) => void;

// the primary code
const primaryCode = () : void =>
{
// created previously
// this is the directory session that will server as primary session
// this DirectorySessionInterface should already be logged in
let lOriginalDirectorySession : DirectorySessionInterface;

// created previously
// this is the data session that will server as primary session
// this DataSessionInterface should already be primary session
let lOriginalDataSession : DataSessionInterface;

// create a secondary session info to init the future secondary DirectorySessionInterface
const lSecondaryDirectorySessionInfo : SecondaryDirectorySessionInterfaceInfo | undefined = lOriginalDirectorySession.requestNewSecondaryDirectorySession();
if(lSecondaryDirectorySessionInfo === undefined)
{
// output some fancy error message
console.error('secondary directory session info creation failed');
return;
}

// create a secondary session info to init the future secondary DataSessionInterface
// warning : this call will hold resources in the primary DataSessionInterface
// when the secondary data session is no longer useful
// release resources with unregisterSecondaryDataSession
// warning: there is a finite number of secondary data sessions that may be created
let lSecondaryDataSessionInfo : SecondaryDataSessionInterfaceInfo | undefined = lOriginalDataSession.requestNewSecondaryDataSession();
if(lSecondaryDataSessionInfo === undefined)
{
// output some fancy error message
console.error('secondary data session info creation failed');
return;
}

// called when the DirectorySessionInterface updates its tokens
const lDirectorySessionTokenUpdate = () : void => {
const lHttpBearer : string = lOriginalDirectorySession.getHttpBearer();
// only update tokens when the directory session is connected
if(lHttpBearer.length > 0)
{
// send the new directory session tokens to the secondary
sendMessage({
type: 'directorySessionTokens',
httpBearer: lHttpBearer,
authenticationBearer: lOriginalDirectorySession.getAuthenticationBearer(),
extendedAuthenticationBearer: lOriginalDirectorySession.getExtendedAuthenticationBearer(),
});
}
};

// called when the DataSessionInterface updates its tokens
const lDataSessionTokenUpdate = () : void => {
const lDataSessionBearer : string = lOriginalDataSession.getDataSessionBearer();
// only update tokens when the data session is connected
if(lDataSessionBearer.length > 0)
{
// send the new data session tokens to the secondary session
sendMessage({
type: 'dataSessionTokens',
dataSessionBearer: lDataSessionBearer,
extendedDataSessionBearer: lOriginalDataSession.getExtendedDataSessionBearer(),
});
}
};

// message callback, receive messages from the secondary session
const onMessage : tMessageHandler = (pMessage : any) : void =>
{
switch(pMessage.type)
{
// cleanup the secondary session resources
case 'dataSessionCleanup':
if(lSecondaryDataSessionInfo !== undefined)
{
lOriginalDataSession.unregisterSecondaryDataSession(lSecondaryDataSessionInfo);
// cleanup only once
lSecondaryDataSessionInfo = undefined;
}
break;
default:
// this should not happen, we have no other message types that we may receive
console.error('Unexpected message type');
break;
}
};

// and register the token update functions on token update
lOriginalDirectorySession.addEventListener(DirectorySessionInterfaceSignal.TokenUpdated, lDirectorySessionTokenUpdate);
lOriginalDataSession.addEventListener(DataSessionInterfaceSignal.TokenUpdated, lDataSessionTokenUpdate);
// register callbacks
registerMessageHandler(onMessage);

// we are ready, send the infos to load a new secondary directory and data session
sendMessage({
type: 'init',
directorySession: lSecondaryDirectorySessionInfo,
dataSession: lSecondaryDataSessionInfo,
// build id is required to create a data session on the correct build
buildId: lOriginalDataSession.getBuildId()
});
};

// the secondary session code
const secondaryCode = () : void =>
{
// create a directory session
const sDirectoryUrl : string = 'https://my_directory:443/directory';
// before connection, this is a "normal" one
const lSecondaryDirectorySession : DirectorySessionInterface = DirectorySessionFactory.CreateDirectorySession(sDirectoryUrl);
// Create a cache to avoid requesting heavy data from the server if data has been retrieved already
const lCache: InfiniteCacheInterface = InfiniteCacheFactory.CreateInfiniteCache();
// the new data session
// we cannot create it right now, we must wait for secondary session info and directory session login
let lSecondaryDataSession : DataSessionInterface;
// hold the open secondary session info for future call
let lSecondaryDataSessionInterfaceInfo : SecondaryDataSessionInterfaceInfo;
// the build id we will be connected to
let lDataSessionBuildId : string = '';

// Success callback on DirectorySessionInterface login
const onLoginSuccess = () : void => {
// weird, we should have a build id at this time
if(lDataSessionBuildId.length === 0)
{
// and output some message if the data session creation failed
console.error('data session creation failed, empty build id');
// and tell the primary session to get rid of the secondary session
sendMessage({ type: 'dataSessionCleanup' });
return;
}
// actually create the DataSessionInterface
lSecondaryDataSession = lSecondaryDirectorySession.createDataSession(lDataSessionBuildId, lCache);
if(lSecondaryDataSession === undefined)
{
// and output some message if the data session creation failed
console.error('data session creation failed');
// and tell the primary session to get rid of the secondary session
sendMessage({ type: 'dataSessionCleanup' });
return;
}
// open it in secondary session mode
if(!lSecondaryDataSession.openSecondaryDataSession(lSecondaryDataSessionInterfaceInfo))
{
// and output some message if the data session opening failed
console.error('secondary data session opening failed');
// get rid of data
lSecondaryDataSession.dispose();
lSecondaryDataSession = undefined;
// and tell the primary session to get rid of the secondary session
sendMessage({ type: 'dataSessionCleanup' });
}
// and then we must wait for the DataSessionInterface to be connected
};

// message callback, receive secondary sessions info and tokens
const onMessage : tMessageHandler = (pMessage : any) : void =>
{
switch(pMessage.type)
{
// secondary sessions infos
case 'init':
{
lSecondaryDataSessionInterfaceInfo = pMessage.dataSession;
lDataSessionBuildId = pMessage.buildId;
const lResult : AuthenticationGetURLResult = lSecondaryDirectorySession.openSecondaryDirectorySession(pMessage.directorySession);
if(lResult !== AuthenticationGetURLResult.AuthenticationPending)
{
// and output some message if the data session opening failed
console.error('directory session opening failed');
// and tell the primary session to get rid of the secondary session
sendMessage({ type: 'dataSessionCleanup' });
}
break;
}
case 'directorySessionTokens':
{
// do nothing if the directory session is not connected
if(!lSecondaryDirectorySession.isAuthenticated())
{
return;
}
// and update the tokens
const lResult : boolean = lSecondaryDirectorySession.setTokenValues(pMessage.httpBearer, pMessage.authenticationBearer, pMessage.extendedAuthenticationBearer);
if(!lResult)
{
// and output some message if the token update failed
console.error('set token values failed');
// and tell the primary session to get rid of the secondary session
sendMessage({ type: 'dataSessionCleanup' });
}
break;
}
case 'dataSessionTokens':
{
// do nothing if the data session is not connected nor created
if(lSecondaryDataSession === undefined || !lSecondaryDataSession.isConnected())
{
return;
}
// and update the tokens
const lResult : boolean = lSecondaryDataSession.setTokenValues(pMessage.dataSessionBearer, pMessage.extendedDataSessionBearer);
if(!lResult)
{
// and output some message if the token update failed
console.error('set token values failed');
// and tell the primary session to get rid of the secondary session
sendMessage({ type: 'dataSessionCleanup' });
}
break;
}
default:
// this should not happen, we have no other message types that we may receive
console.error('Unexpected message type');
break;
}
};

// register callbacks
lSecondaryDirectorySession.addEventListener(DirectorySessionInterfaceSignal.LoginSuccess, onLoginSuccess);
registerMessageHandler(onMessage);
};

// in the primary part
primaryCode();

// in the secondary part
secondaryCode();

or asynchronously :
/** 
* Sample to illustrate the asynchronous use of the primary/secondary session mechanism of DirectorySessionInterface
* and DataSessionInterface.
*/
import {
InfiniteCacheFactory, DirectorySessionFactory,
InfiniteCacheInterface, DirectorySessionInterface,
DataSessionInterface,
DataSessionInterfaceSignal, DirectorySessionInterfaceSignal,
SecondaryDirectorySessionInterfaceInfo,
SecondaryDataSessionInterfaceInfo,
AsyncDirectorySessionWaitForLoadedResult,
AsyncDirectorySessionWaitForLoadedResultReason,
AsyncDataSessionInterfaceOpenResult,
} from 'generated_files/documentation/appinfiniteapi';

// this sample holds the code to be use in the primary tab (primaryCode)
// and in the secondary tab (secondaryCode)

// a callback to receive messages
type tMessageHandler = (pMessage: any) => void;

// we suppose that there exists a message system
let sendMessage : (pMessage: any) => void;

// we suppose that we can register a handler to receive messages
let registerMessageHandler : (pMessageHandler: tMessageHandler) => void;

// the primary code
const primaryCode = () : void =>
{
// created previously
// this is the directory session that will server as primary session
// this DirectorySessionInterface should already be logged in
let lOriginalDirectorySession : DirectorySessionInterface;

// created previously
// this is the data session that will server as primary session
// this DataSessionInterface should already be connected
let lOriginalDataSession : DataSessionInterface;

// create a secondary session info to init the future secondary DirectorySessionInterface
const lSecondaryDirectorySessionInfo : SecondaryDirectorySessionInterfaceInfo | undefined = lOriginalDirectorySession.requestNewSecondaryDirectorySession();
if(lSecondaryDirectorySessionInfo === undefined)
{
// output some fancy error message
console.error('secondary directory session info creation failed');
return;
}

// create a secondary data session info to init the future secondary DataSessionInterface
// warning : this call will hold resources in the primary DataSessionInterface
// when the secondary data session is no longer useful
// release resources with unregisterSecondaryDataSession
// warning: there is a finite number of secondary data sessions that may be created
let lSecondaryDataSessionInfo : SecondaryDataSessionInterfaceInfo | undefined = lOriginalDataSession.requestNewSecondaryDataSession();
if(lSecondaryDataSessionInfo === undefined)
{
// output some fancy error message
console.error('secondary data session info creation failed');
return;
}

// called when the DirectorySessionInterface updates its tokens
const lDirectorySessionTokenUpdate = () : void => {
const lHttpBearer : string = lOriginalDirectorySession.getHttpBearer();
// only update tokens when the directory session is connected
if(lHttpBearer.length > 0)
{
// send the new directory session tokens to the secondary session
sendMessage({
type: 'directorySessionTokens',
httpBearer: lHttpBearer,
authenticationBearer: lOriginalDirectorySession.getAuthenticationBearer(),
extendedAuthenticationBearer: lOriginalDirectorySession.getExtendedAuthenticationBearer(),
});
}
};

// called when the DataSessionInterface updates its tokens
const lDataSessionTokenUpdate = () : void => {
const lDataSessionBearer : string = lOriginalDataSession.getDataSessionBearer();
// only update tokens when the data session is connected
if(lDataSessionBearer.length > 0)
{
// send the new data session tokens to the secondary session
sendMessage({
type: 'dataSessionTokens',
dataSessionBearer: lDataSessionBearer,
extendedDataSessionBearer: lOriginalDataSession.getExtendedDataSessionBearer(),
});
}
};

// message callback, receive messages from the secondary session
const onMessage : tMessageHandler = (pMessage : any) : void =>
{
switch(pMessage.type)
{
// cleanup the secondary data session resources
case 'dataSessionCleanup':
if(lSecondaryDataSessionInfo !== undefined)
{
lOriginalDataSession.unregisterSecondaryDataSession(lSecondaryDataSessionInfo);
// cleanup only once
lSecondaryDataSessionInfo = undefined;
}
break;
default:
// this should not happen, we have no other message types that we may receive
console.error('Unexpected message type');
break;
}
};

// and register the token update functions on token update
lOriginalDirectorySession.addEventListener(DirectorySessionInterfaceSignal.TokenUpdated, lDirectorySessionTokenUpdate);
lOriginalDataSession.addEventListener(DataSessionInterfaceSignal.TokenUpdated, lDataSessionTokenUpdate);
// register callbacks
registerMessageHandler(onMessage);

// we are ready, send the infos to load a new secondary directory and data session
sendMessage({
type: 'init',
directorySession: lSecondaryDirectorySessionInfo,
dataSession: lSecondaryDataSessionInfo,
// build id is required to create a data session on the correct build
buildId: lOriginalDataSession.getBuildId()
});
};

// the secondary session code
const secondaryCode = () : void =>
{
// create a directory session
const sDirectoryUrl : string = 'https://my_directory:443/directory';
// before connection, this is a "normal" one
const lSecondaryDirectorySession : DirectorySessionInterface = DirectorySessionFactory.CreateDirectorySession(sDirectoryUrl);
// Create a cache to avoid requesting heavy data from the server if data has been retrieved already
const lCache: InfiniteCacheInterface = InfiniteCacheFactory.CreateInfiniteCache();
// the new data session
// we cannot create it right now, we must wait for secondary session info and directory session login
let lSecondaryDataSession : DataSessionInterface;
// hold the open secondary info for future call
let lSecondaryDataSessionInterfaceInfo : SecondaryDataSessionInterfaceInfo;
// the build id we will be connected to
let lDataSessionBuildId : string = '';

// message callback, receive secondary sessions info and tokens
const onMessage : tMessageHandler = (pMessage : any) : void =>
{
switch(pMessage.type)
{
// secondary sessions infos
case 'init':
{
lSecondaryDataSessionInterfaceInfo = pMessage.dataSession;
lDataSessionBuildId = pMessage.buildId;
lSecondaryDirectorySession.asyncOpenSecondaryDirectorySession(pMessage.directorySession).then(
(pOpenResult: AsyncDirectorySessionWaitForLoadedResult) : void => {
if(pOpenResult.reason !== AsyncDirectorySessionWaitForLoadedResultReason.OpenResult_LoginSuccess)
{
// and output some message if the data session opening failed
console.error('directory session opening failed');
// and tell the primary session to get rid of the secondary session
sendMessage({ type: 'dataSessionCleanup' });
return;
}
// weird, we should have a build id at this time
if(lDataSessionBuildId.length === 0)
{
// and output some message if the data session creation failed
console.error('data session creation failed, empty build id');
// and tell the primary session to get rid of the secondary session
sendMessage({ type: 'dataSessionCleanup' });
return;
}
// actually create the DataSessionInterface
lSecondaryDataSession = lSecondaryDirectorySession.createDataSession(lDataSessionBuildId, lCache);
if(lSecondaryDataSession === undefined)
{
// and output some message if the data session creation failed
console.error('data session creation failed');
// and tell the primary session to get rid of the secondary session
sendMessage({ type: 'dataSessionCleanup' });
return;
}
// open it in secondary session mode
lSecondaryDataSession.asyncOpenSecondaryDataSession(lSecondaryDataSessionInterfaceInfo).then(
(pDataSessionResult: AsyncDataSessionInterfaceOpenResult) : void =>
{
if(pDataSessionResult !== AsyncDataSessionInterfaceOpenResult.OpenResult_Success)
{
// and output some message if the data session opening failed
console.error('secondary data session opening failed');
// get rid of data
lSecondaryDataSession.dispose();
lSecondaryDataSession = undefined;
// and tell the primary session to get rid of the secondary session
sendMessage({ type: 'dataSessionCleanup' });
}
// and do some fancy things there :)
// we are connected correctly
}
);
}
);
break;
}
case 'directorySessionTokens':
{
// do nothing if the directory session is not connected
if(!lSecondaryDirectorySession.isAuthenticated())
{
return;
}
// and update the tokens
const lResult : boolean = lSecondaryDirectorySession.setTokenValues(pMessage.httpBearer, pMessage.authenticationBearer, pMessage.extendedAuthenticationBearer);
if(!lResult)
{
// and output some message if the token update failed
console.error('set token values failed');
// and tell the primary session to get rid of the secondary session
sendMessage({ type: 'dataSessionCleanup' });
}
break;
}
case 'dataSessionTokens':
{
// do nothing if the data session is not connected nor created
if(lSecondaryDataSession === undefined || !lSecondaryDataSession.isConnected())
{
return;
}
// and update the tokens
const lResult : boolean = lSecondaryDataSession.setTokenValues(pMessage.dataSessionBearer, pMessage.extendedDataSessionBearer);
if(!lResult)
{
// and output some message if the token update failed
console.error('set token values failed');
// and tell the primary session to get rid of the secondary session
sendMessage({ type: 'dataSessionCleanup' });
}
break;
}
default:
// this should not happen, we have no other message types that we may receive
console.error('Unexpected message type');
break;
}
};

// register callbacks
registerMessageHandler(onMessage);
};

// in the primary part
primaryCode();

// in the secondary part
secondaryCode();

Please keep in mind that only a finite number of secondary DataSessionInterface may be created, indeed, creating a secondary DataSessionInterface holds resources on the primary DataSessionInterface. Thus, it is required to call unregisterSecondaryDataSession on the primary DataSessionInterface when a secondary DataSessionInterface is no longer in use.
Sessions

interface DataSessionInterface {
    addEventListener(pType, pListener, pObject): string;
    addEventListener(pType, pListener): string;
    areSignalsBlocked(): boolean;
    asyncCloseDataSession(): Promise<void>;
    asyncOpenDataSession(pRestrictionTags?, pAddedScopes?): Promise<AsyncDataSessionInterfaceOpenResult>;
    asyncOpenSecondaryDataSession(pSecondarySessionInfo): Promise<AsyncDataSessionInterfaceOpenResult>;
    bindInfiniteEngine(pEngine): boolean;
    blockSignals(pBlock): void;
    cancelUpdate(): void;
    closeDataSession(): void;
    convertUnitFactor(pFrom, pTo): number;
    createAnnotationGetter(): AnnotationGetterInterface;
    createAnnotationView(pAnnotationViewData): AnnotationViewInterface;
    createAttachedDocumentInfo(): AttachedDocumentInfoInterface;
    createAttributeValuesEnumerator(pObjectId?): AttributeValuesEnumeratorInterface;
    createChildrenIdCardGetter(): ChildrenIdCardGetterInterface;
    createDocumentContentGetter(): DocumentContentGetterInterface;
    createDocumentIdConverter(): DocumentIdConverterInterface;
    createFilterAABB(pFilterId?): FilterAABBInterface;
    createFilterAllParts(pFilterId?): FilterAllPartsInterface;
    createFilterAttribute(pFilterId?): FilterAttributeInterface;
    createFilterBoolean(pFilterId?): FilterBooleanInterface;
    createFilterCompound(pFilterId?): FilterCompoundInterface;
    createFilterDiagonal(pFilterId?): FilterDiagonalInterface;
    createFilterHasField(pFilterId?): FilterHasFieldInterface;
    createFilterLiteral(pFilterId?): FilterLiteralInterface;
    createFilterPartInstanceList(pFilterId?): FilterPartInstanceListInterface;
    createFilterRange(pFilterId?): FilterRangeInterface;
    createFilterSet(pFilterId?): FilterSetInterface;
    createGeometricInstanceConverter(): GeometricInstanceConverterInterface;
    createIdCardGetter(): IdCardGetterInterface;
    createPartInstanceConverter(): PartInstanceConverterInterface;
    createPartInstanceMatrixGetter(): PartInstanceMatrixGetterInterface;
    createSearch(): SearchInterface;
    createWorkingSet(pRetrievalMode, pWorkingSetBehavior, pWorkingSetId?): WorkingSetInterface;
    dispose(): void;
    export2D(pWorkingSetList, pFormat, pCutPlanes?, pApplicationId?): ExportJobInterface;
    export3D(pWorkingSetList, pFormat, pApplicationId?): ExportJobInterface;
    exportSVG(pWorkingSetList, pFormat, pCutPlanes?, pApplicationId?): ExportJobInterface;
    fromJSON(pAllData): boolean;
    getAnnotationTypes(): string[];
    getAttributesDictionary(): AttributesDictionaryInterface;
    getBoundInfiniteEngines(pEngines): boolean;
    getBuildId(): string;
    getConfigurationList(): ConfigurationInterface[];
    getDataSessionBearer(): string;
    getDataSessionId(): string;
    getDmuAABB(pDmuAABBOut): boolean;
    getDmuBuildUnit(): Unit;
    getExportProcedures(pExportJobs): boolean;
    getExtendedDataSessionBearer(): string;
    getGeometricAABB(pGeometricInstanceId, pAABBOut): boolean;
    getGeometricOBBDiagonalSquaredLength(pGeometricInstanceId): number;
    getGeometricOBBDiagonalSquaredMax(): number;
    getGeometricOBBDiagonalSquaredMin(): number;
    getGrantedScopes(pScopes): void;
    getGrantedSecurityTags(pTags): void;
    getInfiniteObjectType(): InfiniteObjectType;
    getMaximumGeometricId(): number;
    getMaximumPartInstanceLeafId(): number;
    getOpenSessionProgress(): number;
    getOriginalGeometricMatrix(pGeometricInstanceId, pMatrixOut): boolean;
    getProjectDocument(pDocumentId): string;
    getProxyUrl(): string;
    getSourceModelId(pGeometricInstanceId): number;
    getUnitedAABB(pGeometricInstanceIds, pAABBOut): boolean;
    getWorkingSetById(pWorkingSetId): WorkingSetInterface;
    getWorkingSets(pWorkingSets): void;
    hasEventListener(pType, pListener): boolean;
    hasEventListenerById(pId): boolean;
    hasFeatures(): boolean;
    isConnected(): boolean;
    isDisposed(): boolean;
    isLoaded(): boolean;
    isPrimaryBehavior(): boolean;
    openDataSession(pRestrictionTags?, pAddedScopes?): boolean;
    openSecondaryDataSession(pSecondarySessionInfo): boolean;
    removeAllEventListeners(): boolean;
    removeEventListener(pType, pListener, pObject): boolean;
    removeEventListener(pType, pListener): boolean;
    removeEventListenerById(pId): boolean;
    requestNewSecondaryDataSession(): SecondaryDataSessionInterfaceInfo;
    restartIdleTimer(): void;
    setTokenValues(pDataSessionBearer, pExtendedDataSessionBearer): boolean;
    toJSON(pKey?): Object;
    unbindInfiniteEngine(pEngine): boolean;
    unregisterSecondaryDataSession(pSecondarySessionInfo): boolean;
    update(): void;
}

Hierarchy (view full)

Methods

addEventListener areSignalsBlocked asyncCloseDataSession asyncOpenDataSession asyncOpenSecondaryDataSession bindInfiniteEngine blockSignals cancelUpdate closeDataSession convertUnitFactor createAnnotationGetter createAnnotationView createAttachedDocumentInfo createAttributeValuesEnumerator createChildrenIdCardGetter createDocumentContentGetter createDocumentIdConverter createFilterAABB createFilterAllParts createFilterAttribute createFilterBoolean createFilterCompound createFilterDiagonal createFilterHasField createFilterLiteral createFilterPartInstanceList createFilterRange createFilterSet createGeometricInstanceConverter createIdCardGetter createPartInstanceConverter createPartInstanceMatrixGetter createSearch createWorkingSet dispose export2D export3D exportSVG fromJSON getAnnotationTypes getAttributesDictionary getBoundInfiniteEngines getBuildId getConfigurationList getDataSessionBearer getDataSessionId getDmuAABB getDmuBuildUnit getExportProcedures getExtendedDataSessionBearer getGeometricAABB getGeometricOBBDiagonalSquaredLength getGeometricOBBDiagonalSquaredMax getGeometricOBBDiagonalSquaredMin getGrantedScopes getGrantedSecurityTags getInfiniteObjectType getMaximumGeometricId getMaximumPartInstanceLeafId getOpenSessionProgress getOriginalGeometricMatrix getProjectDocument getProxyUrl getSourceModelId getUnitedAABB getWorkingSetById getWorkingSets hasEventListener hasEventListenerById hasFeatures isConnected isDisposed isLoaded isPrimaryBehavior openDataSession openSecondaryDataSession removeAllEventListeners removeEventListener removeEventListenerById requestNewSecondaryDataSession restartIdleTimer setTokenValues toJSON unbindInfiniteEngine unregisterSecondaryDataSession update

Methods

  • Adds a listener to an event type.

    When an event of the type pType fires, the callback pListener will be called. This function returns a unique string id that may be used in removeEventListenerById to allow simple listener removal. It is possible to add an object that will be included in the callback to avoid creating too many closures. Calling twice addEventListener with the same parameters results in the second call to be ignored, only unique pairs callback / object are allowed, in order to avoid calling multiple times the same thing.

    Parameters

    • pType: string
      in
      The type of the event pListener will be called upon.
    • pListener: tListenerCallback
      in
      The listener function that fires when the given event type occurs.
    • pObject: Object
      in
      The optional object the callback will be called with when the given event fires.

    Returns string

    The id of the inserted callback (actually an UUID).

  • Adds a listener to an event type.

    When an event of the type pType fires, the callback pListener will be called. This function returns a unique string id that may be used in removeEventListenerById to allow simple listener removal.

    Parameters

    • pType: string
      in
      The type of the event pListener will be called upon.
    • pListener: tListenerCallback
      in
      The listener function that fires when the given event type occurs.

    Returns string

    The id of the inserted callback (actually an UUID).

  • Tells if signals sent by the object are blocked or not.

    If signals are blocked, no signal will be emitted nor buffered, such signal will be lost.

    Returns boolean

    true if signals are blocked.

  • Asynchronous - Sends a close request concerning the current data session on the proxy.

    This actually cleans up the data retained by the proxy and cleans up the resources allocated to the InfiniteEngineInterface.

    When the data session is effectively closed, the promise is resolved.

    Returns Promise<void>

    A promise.

  • Asynchronous - starts the open data session procedure.

    A connection is established between the client and the 3djuump Infinite proxy. Security tokens are exchanged and initialization data is retrieved from the proxy and the cache if relevant. This operation may take from a few seconds to several minutes depending on the size of the build to work with.

    Additional functionalities may be required with pAddedScopes. When opening a data session, the user may request the rights to :

    • Download evojuump files.
    • Export 2d files.
    • Export 3d files. Granted scopes are available with getGrantedScopes.

    The promise is then resolved with the correct AsyncDataSessionInterfaceOpenResult value.

    Parameters

    • Optional pRestrictionTags: string[]
      in
      If set, the data session will be opened with less security tags the user is allowed to use. An intersection with the user security tags, the build security tags and pRestrictionTags is set, and the resulting security tags are used to open the 3djuump build.
    • Optional pAddedScopes: DataSessionInterfaceScopes[]
      in
      If set, the data session wil be open with available added functionalities (DataSessionInterfaceScopes).

    Returns Promise<AsyncDataSessionInterfaceOpenResult>

    A promise. The promise is resolved with the reason (success, failed, already closed).

  • Asynchronously opens a DataSessionInterface in secondary data session mode.

    Once a DataSessionInterface has been fully loaded with openDataSession, a secondary DataSessionInterface may be open with asyncOpenSecondaryDataSession with the result of requestNewSecondaryDataSession called on the primary DataSessionInterface.

    /** 
    * Sample to illustrate the asynchronous use of the primary/secondary session mechanism of DirectorySessionInterface
    * and DataSessionInterface.
    */
    import {
    InfiniteCacheFactory, DirectorySessionFactory,
    InfiniteCacheInterface, DirectorySessionInterface,
    DataSessionInterface,
    DataSessionInterfaceSignal, DirectorySessionInterfaceSignal,
    SecondaryDirectorySessionInterfaceInfo,
    SecondaryDataSessionInterfaceInfo,
    AsyncDirectorySessionWaitForLoadedResult,
    AsyncDirectorySessionWaitForLoadedResultReason,
    AsyncDataSessionInterfaceOpenResult,
    } from 'generated_files/documentation/appinfiniteapi';

    // this sample holds the code to be use in the primary tab (primaryCode)
    // and in the secondary tab (secondaryCode)

    // a callback to receive messages
    type tMessageHandler = (pMessage: any) => void;

    // we suppose that there exists a message system
    let sendMessage : (pMessage: any) => void;

    // we suppose that we can register a handler to receive messages
    let registerMessageHandler : (pMessageHandler: tMessageHandler) => void;

    // the primary code
    const primaryCode = () : void =>
    {
    // created previously
    // this is the directory session that will server as primary session
    // this DirectorySessionInterface should already be logged in
    let lOriginalDirectorySession : DirectorySessionInterface;

    // created previously
    // this is the data session that will server as primary session
    // this DataSessionInterface should already be connected
    let lOriginalDataSession : DataSessionInterface;

    // create a secondary session info to init the future secondary DirectorySessionInterface
    const lSecondaryDirectorySessionInfo : SecondaryDirectorySessionInterfaceInfo | undefined = lOriginalDirectorySession.requestNewSecondaryDirectorySession();
    if(lSecondaryDirectorySessionInfo === undefined)
    {
    // output some fancy error message
    console.error('secondary directory session info creation failed');
    return;
    }

    // create a secondary data session info to init the future secondary DataSessionInterface
    // warning : this call will hold resources in the primary DataSessionInterface
    // when the secondary data session is no longer useful
    // release resources with unregisterSecondaryDataSession
    // warning: there is a finite number of secondary data sessions that may be created
    let lSecondaryDataSessionInfo : SecondaryDataSessionInterfaceInfo | undefined = lOriginalDataSession.requestNewSecondaryDataSession();
    if(lSecondaryDataSessionInfo === undefined)
    {
    // output some fancy error message
    console.error('secondary data session info creation failed');
    return;
    }

    // called when the DirectorySessionInterface updates its tokens
    const lDirectorySessionTokenUpdate = () : void => {
    const lHttpBearer : string = lOriginalDirectorySession.getHttpBearer();
    // only update tokens when the directory session is connected
    if(lHttpBearer.length > 0)
    {
    // send the new directory session tokens to the secondary session
    sendMessage({
    type: 'directorySessionTokens',
    httpBearer: lHttpBearer,
    authenticationBearer: lOriginalDirectorySession.getAuthenticationBearer(),
    extendedAuthenticationBearer: lOriginalDirectorySession.getExtendedAuthenticationBearer(),
    });
    }
    };

    // called when the DataSessionInterface updates its tokens
    const lDataSessionTokenUpdate = () : void => {
    const lDataSessionBearer : string = lOriginalDataSession.getDataSessionBearer();
    // only update tokens when the data session is connected
    if(lDataSessionBearer.length > 0)
    {
    // send the new data session tokens to the secondary session
    sendMessage({
    type: 'dataSessionTokens',
    dataSessionBearer: lDataSessionBearer,
    extendedDataSessionBearer: lOriginalDataSession.getExtendedDataSessionBearer(),
    });
    }
    };

    // message callback, receive messages from the secondary session
    const onMessage : tMessageHandler = (pMessage : any) : void =>
    {
    switch(pMessage.type)
    {
    // cleanup the secondary data session resources
    case 'dataSessionCleanup':
    if(lSecondaryDataSessionInfo !== undefined)
    {
    lOriginalDataSession.unregisterSecondaryDataSession(lSecondaryDataSessionInfo);
    // cleanup only once
    lSecondaryDataSessionInfo = undefined;
    }
    break;
    default:
    // this should not happen, we have no other message types that we may receive
    console.error('Unexpected message type');
    break;
    }
    };

    // and register the token update functions on token update
    lOriginalDirectorySession.addEventListener(DirectorySessionInterfaceSignal.TokenUpdated, lDirectorySessionTokenUpdate);
    lOriginalDataSession.addEventListener(DataSessionInterfaceSignal.TokenUpdated, lDataSessionTokenUpdate);
    // register callbacks
    registerMessageHandler(onMessage);

    // we are ready, send the infos to load a new secondary directory and data session
    sendMessage({
    type: 'init',
    directorySession: lSecondaryDirectorySessionInfo,
    dataSession: lSecondaryDataSessionInfo,
    // build id is required to create a data session on the correct build
    buildId: lOriginalDataSession.getBuildId()
    });
    };

    // the secondary session code
    const secondaryCode = () : void =>
    {
    // create a directory session
    const sDirectoryUrl : string = 'https://my_directory:443/directory';
    // before connection, this is a "normal" one
    const lSecondaryDirectorySession : DirectorySessionInterface = DirectorySessionFactory.CreateDirectorySession(sDirectoryUrl);
    // Create a cache to avoid requesting heavy data from the server if data has been retrieved already
    const lCache: InfiniteCacheInterface = InfiniteCacheFactory.CreateInfiniteCache();
    // the new data session
    // we cannot create it right now, we must wait for secondary session info and directory session login
    let lSecondaryDataSession : DataSessionInterface;
    // hold the open secondary info for future call
    let lSecondaryDataSessionInterfaceInfo : SecondaryDataSessionInterfaceInfo;
    // the build id we will be connected to
    let lDataSessionBuildId : string = '';

    // message callback, receive secondary sessions info and tokens
    const onMessage : tMessageHandler = (pMessage : any) : void =>
    {
    switch(pMessage.type)
    {
    // secondary sessions infos
    case 'init':
    {
    lSecondaryDataSessionInterfaceInfo = pMessage.dataSession;
    lDataSessionBuildId = pMessage.buildId;
    lSecondaryDirectorySession.asyncOpenSecondaryDirectorySession(pMessage.directorySession).then(
    (pOpenResult: AsyncDirectorySessionWaitForLoadedResult) : void => {
    if(pOpenResult.reason !== AsyncDirectorySessionWaitForLoadedResultReason.OpenResult_LoginSuccess)
    {
    // and output some message if the data session opening failed
    console.error('directory session opening failed');
    // and tell the primary session to get rid of the secondary session
    sendMessage({ type: 'dataSessionCleanup' });
    return;
    }
    // weird, we should have a build id at this time
    if(lDataSessionBuildId.length === 0)
    {
    // and output some message if the data session creation failed
    console.error('data session creation failed, empty build id');
    // and tell the primary session to get rid of the secondary session
    sendMessage({ type: 'dataSessionCleanup' });
    return;
    }
    // actually create the DataSessionInterface
    lSecondaryDataSession = lSecondaryDirectorySession.createDataSession(lDataSessionBuildId, lCache);
    if(lSecondaryDataSession === undefined)
    {
    // and output some message if the data session creation failed
    console.error('data session creation failed');
    // and tell the primary session to get rid of the secondary session
    sendMessage({ type: 'dataSessionCleanup' });
    return;
    }
    // open it in secondary session mode
    lSecondaryDataSession.asyncOpenSecondaryDataSession(lSecondaryDataSessionInterfaceInfo).then(
    (pDataSessionResult: AsyncDataSessionInterfaceOpenResult) : void =>
    {
    if(pDataSessionResult !== AsyncDataSessionInterfaceOpenResult.OpenResult_Success)
    {
    // and output some message if the data session opening failed
    console.error('secondary data session opening failed');
    // get rid of data
    lSecondaryDataSession.dispose();
    lSecondaryDataSession = undefined;
    // and tell the primary session to get rid of the secondary session
    sendMessage({ type: 'dataSessionCleanup' });
    }
    // and do some fancy things there :)
    // we are connected correctly
    }
    );
    }
    );
    break;
    }
    case 'directorySessionTokens':
    {
    // do nothing if the directory session is not connected
    if(!lSecondaryDirectorySession.isAuthenticated())
    {
    return;
    }
    // and update the tokens
    const lResult : boolean = lSecondaryDirectorySession.setTokenValues(pMessage.httpBearer, pMessage.authenticationBearer, pMessage.extendedAuthenticationBearer);
    if(!lResult)
    {
    // and output some message if the token update failed
    console.error('set token values failed');
    // and tell the primary session to get rid of the secondary session
    sendMessage({ type: 'dataSessionCleanup' });
    }
    break;
    }
    case 'dataSessionTokens':
    {
    // do nothing if the data session is not connected nor created
    if(lSecondaryDataSession === undefined || !lSecondaryDataSession.isConnected())
    {
    return;
    }
    // and update the tokens
    const lResult : boolean = lSecondaryDataSession.setTokenValues(pMessage.dataSessionBearer, pMessage.extendedDataSessionBearer);
    if(!lResult)
    {
    // and output some message if the token update failed
    console.error('set token values failed');
    // and tell the primary session to get rid of the secondary session
    sendMessage({ type: 'dataSessionCleanup' });
    }
    break;
    }
    default:
    // this should not happen, we have no other message types that we may receive
    console.error('Unexpected message type');
    break;
    }
    };

    // register callbacks
    registerMessageHandler(onMessage);
    };

    // in the primary part
    primaryCode();

    // in the secondary part
    secondaryCode();

    Parameters

    Returns Promise<AsyncDataSessionInterfaceOpenResult>

    A promise. The promise is resolved with the reason (success, failed, already closed).

  • Blocks / Unblocks all signals sent by the object.

    If signals are blocked, no signal will be emitted nor buffered, such signal will be lost.

    Parameters

    • pBlock: boolean
      in
      If set to true, all further signals will be silently discarded.

    Returns void

  • Cancels the calculation of all running WorkingSetInterfaces, FilterItemInterfaces.

    The relevant interfaces will asynchronously trigger a "cancel" and "ready" signal when the canceling is done.

    Returns void

  • Sends a close request concerning the current data session on the proxy.

    This actually cleans up the data retained by the proxy and cleans up the resources allocated to the InfiniteEngineInterface.

    When the data session is effectively closed, then the DataSessionInterfaceSignal.DataSessionClosed signal is sent.

    Returns void

  • Gets the conversion ratio between two units.

    Parameters

    • pFrom: Unit
      in
      The reference Unit where the conversion starts from.
    • pTo: Unit
      in
      The Unit to convert to.

    Returns number

    A floating number corresponding to the Unit conversion ratio.

  • Instantiates a data retrieval procedure to retrieve the metadata documents associated to a list of part instance ids and their ancestors.

    Such a list of metadata documents can be merged and customized to display an "id-card" of a part instance and its ancestors.

    Returns IdCardGetterInterface

    A new IdCardGetterInterface, undefined if the DMU is not loaded.

  • Sets the content of the DataSessionInterface from a former call to toJSON.

    This call will reuse all available WorkingSetInterface (resetting WorkingSetInterface.blockSignals) and filters to match the given context definition.

    {
    "$defs": {
    "all": {
    "additionalProperties": false,
    "properties": {
    "enabled": {
    "default": true,
    "description": "If disabled, this filter is completely ignored during all the computations",
    "example": true,
    "type": "boolean"
    },
    "id": {
    "description": "an object id : only ascii non control and non blank characters",
    "example": "123e4567e89b12d3a456426614174000",
    "maxLength": 64,
    "pattern": "^[\\x21-\\x7E]{1,64}$",
    "type": "string"
    },
    "inverted": {
    "description": "When 'inverted', a filter elects all the `part instances` that would not be selected if it was not inverted.",
    "example": true,
    "type": "boolean"
    },
    "operator": {
    "default": "and",
    "description": "Operator to apply with this filter and its closest enabled predecessor in its parent container.",
    "enum": [
    "or",
    "and",
    "minus"
    ],
    "example": "or",
    "type": "string"
    },
    "type": {
    "const": "all",
    "description": "Type of the filter",
    "type": "string"
    },
    "version": {
    "description": "Define the version of the object",
    "example": 1,
    "type": "integer"
    }
    },
    "required": [
    "type",
    "operator",
    "enabled",
    "inverted",
    "id"
    ],
    "title": "Filter all definition",
    "type": "object"
    },
    "attribute": {
    "additionalProperties": false,
    "properties": {
    "attribute": {
    "description": "Name of the attribute to filter with",
    "example": "PartNumber",
    "minLength": 0,
    "type": "string"
    },
    "containsValues": {
    "description": "Elects all the `part instances` having the attribute whose name set with attribute in their `joined attribute set` that have a value that contains at least one of the values in the given string array",
    "items": {
    "type": "string"
    },
    "type": "array"
    },
    "enabled": {
    "default": true,
    "description": "If disabled, this filter is completely ignored during all the computations",
    "example": true,
    "type": "boolean"
    },
    "exactValues": {
    "description": "Elects all the `part instances` having the attribute whose name set with `attribute` in their `joined attribute set` that have a value exactly included in the given string array.",
    "items": {
    "type": "string"
    },
    "type": "array"
    },
    "id": {
    "description": "an object id : only ascii non control and non blank characters",
    "example": "123e4567e89b12d3a456426614174000",
    "maxLength": 64,
    "pattern": "^[\\x21-\\x7E]{1,64}$",
    "type": "string"
    },
    "inverted": {
    "description": "When 'inverted', a filter elects all the `part instances` that would not be selected if it was not inverted.",
    "example": true,
    "type": "boolean"
    },
    "na": {
    "description": "Include `part instances` with the `N/A` value",
    "type": "boolean"
    },
    "operator": {
    "default": "and",
    "description": "Operator to apply with this filter and its closest enabled predecessor in its parent container.",
    "enum": [
    "or",
    "and",
    "minus"
    ],
    "example": "or",
    "type": "string"
    },
    "type": {
    "const": "attribute",
    "description": "Type of the filter",
    "type": "string"
    },
    "version": {
    "description": "Define the version of the object",
    "example": 1,
    "type": "integer"
    }
    },
    "required": [
    "type",
    "enabled",
    "operator",
    "inverted",
    "exactValues",
    "containsValues",
    "na",
    "attribute",
    "id"
    ],
    "title": "Filter attribute definition",
    "type": "object"
    },
    "boolean": {
    "additionalProperties": false,
    "properties": {
    "attribute": {
    "description": "Name of the attribute to filter with",
    "example": "PartNumber",
    "minLength": 0,
    "type": "string"
    },
    "enabled": {
    "default": true,
    "description": "If disabled, this filter is completely ignored during all the computations",
    "example": true,
    "type": "boolean"
    },
    "id": {
    "description": "an object id : only ascii non control and non blank characters",
    "example": "123e4567e89b12d3a456426614174000",
    "maxLength": 64,
    "pattern": "^[\\x21-\\x7E]{1,64}$",
    "type": "string"
    },
    "inverted": {
    "description": "When 'inverted', a filter elects all the `part instances` that would not be selected if it was not inverted.",
    "example": true,
    "type": "boolean"
    },
    "operator": {
    "default": "and",
    "description": "Operator to apply with this filter and its closest enabled predecessor in its parent container.",
    "enum": [
    "or",
    "and",
    "minus"
    ],
    "example": "or",
    "type": "string"
    },
    "type": {
    "const": "boolean",
    "description": "Type of the filter",
    "type": "string"
    },
    "value": {
    "default": false,
    "description": "Boolean value of the filter",
    "example": false,
    "type": "boolean"
    },
    "version": {
    "description": "Define the version of the object",
    "example": 1,
    "type": "integer"
    }
    },
    "required": [
    "type",
    "operator",
    "enabled",
    "inverted",
    "attribute",
    "value",
    "id"
    ],
    "title": "Filter boolean definition",
    "type": "object"
    },
    "box": {
    "additionalProperties": false,
    "properties": {
    "enabled": {
    "default": true,
    "description": "If disabled, this filter is completely ignored during all the computations",
    "example": true,
    "type": "boolean"
    },
    "id": {
    "description": "an object id : only ascii non control and non blank characters",
    "example": "123e4567e89b12d3a456426614174000",
    "maxLength": 64,
    "pattern": "^[\\x21-\\x7E]{1,64}$",
    "type": "string"
    },
    "inverted": {
    "description": "When 'inverted', a filter elects all the `part instances` that would not be selected if it was not inverted.",
    "example": true,
    "type": "boolean"
    },
    "max": {
    "description": "Define the coordinates [x,y,z] of the max point of the AABB",
    "items": {
    "type": "number"
    },
    "maxItems": 3,
    "minItems": 3,
    "type": "array"
    },
    "min": {
    "description": "Define the coordinates [x,y,z] of the min point of the AABB",
    "items": {
    "type": "number"
    },
    "maxItems": 3,
    "minItems": 3,
    "type": "array"
    },
    "operator": {
    "default": "and",
    "description": "Operator to apply with this filter and its closest enabled predecessor in its parent container.",
    "enum": [
    "or",
    "and",
    "minus"
    ],
    "example": "or",
    "type": "string"
    },
    "overlap": {
    "description": "Specify if AABB test is included or overlap",
    "example": true,
    "type": "boolean"
    },
    "precision": {
    "description": "Numeric precision will be subtracted/added to min/max point of AABB",
    "type": "number"
    },
    "type": {
    "const": "box",
    "description": "Type of the filter",
    "type": "string"
    },
    "version": {
    "description": "Define the version of the object",
    "example": 1,
    "type": "integer"
    }
    },
    "required": [
    "type",
    "operator",
    "inverted",
    "enabled",
    "min",
    "max",
    "overlap",
    "precision",
    "id"
    ],
    "title": "Filter box definition",
    "type": "object"
    },
    "compound": {
    "additionalProperties": false,
    "properties": {
    "enabled": {
    "default": true,
    "description": "If disabled, this filter is completely ignored during all the computations",
    "example": true,
    "type": "boolean"
    },
    "id": {
    "description": "an object id : only ascii non control and non blank characters",
    "example": "123e4567e89b12d3a456426614174000",
    "maxLength": 64,
    "pattern": "^[\\x21-\\x7E]{1,64}$",
    "type": "string"
    },
    "inverted": {
    "description": "When 'inverted', a filter elects all the `part instances` that would not be selected if it was not inverted.",
    "example": true,
    "type": "boolean"
    },
    "operator": {
    "default": "and",
    "description": "Operator to apply with this filter and its closest enabled predecessor in its parent container.",
    "enum": [
    "or",
    "and",
    "minus"
    ],
    "example": "or",
    "type": "string"
    },
    "subfilters": {
    "description": "list of metadata sub filters",
    "items": {
    "$ref": "#/$defs/compoundfilters"
    },
    "type": "array"
    },
    "type": {
    "const": "compound",
    "description": "Type of the filter",
    "type": "string"
    },
    "version": {
    "description": "Define the version of the object",
    "example": 1,
    "type": "integer"
    }
    },
    "required": [
    "type",
    "operator",
    "enabled",
    "inverted",
    "subfilters",
    "id"
    ],
    "title": "Filter compound definition",
    "type": "object"
    },
    "compoundfilters": {
    "oneOf": [
    {
    "$ref": "#/$defs/boolean"
    },
    {
    "$ref": "#/$defs/hasfield"
    },
    {
    "$ref": "#/$defs/attribute"
    },
    {
    "$ref": "#/$defs/range"
    }
    ]
    },
    "datasessioncontext": {
    "additionalProperties": false,
    "properties": {
    "type": {
    "const": "datasessioncontext",
    "description": "Type of context",
    "type": "string"
    },
    "version": {
    "description": "Define the version of the object",
    "example": 1,
    "type": "integer"
    },
    "workingsets": {
    "description": "List of working sets",
    "items": {
    "$ref": "#/$defs/workingset"
    },
    "type": "array"
    }
    },
    "required": [
    "type",
    "version",
    "workingsets"
    ],
    "type": "object"
    },
    "dependencyItem": {
    "additionalProperties": false,
    "properties": {
    "id": {
    "description": "an object id : only ascii non control and non blank characters",
    "example": "123e4567e89b12d3a456426614174000",
    "maxLength": 64,
    "pattern": "^[\\x21-\\x7E]{1,64}$",
    "type": "string"
    },
    "op": {
    "default": "and",
    "description": "Operator to apply with this filter and its closest enabled predecessor in its parent container.",
    "enum": [
    "or",
    "and",
    "minus"
    ],
    "example": "or",
    "type": "string"
    }
    },
    "required": [
    "op",
    "id"
    ],
    "type": "object"
    },
    "diagonal": {
    "additionalProperties": false,
    "properties": {
    "enabled": {
    "default": true,
    "description": "If disabled, this filter is completely ignored during all the computations",
    "example": true,
    "type": "boolean"
    },
    "id": {
    "description": "an object id : only ascii non control and non blank characters",
    "example": "123e4567e89b12d3a456426614174000",
    "maxLength": 64,
    "pattern": "^[\\x21-\\x7E]{1,64}$",
    "type": "string"
    },
    "inverted": {
    "description": "When 'inverted', a filter elects all the `part instances` that would not be selected if it was not inverted.",
    "example": true,
    "type": "boolean"
    },
    "operator": {
    "default": "and",
    "description": "Operator to apply with this filter and its closest enabled predecessor in its parent container.",
    "enum": [
    "or",
    "and",
    "minus"
    ],
    "example": "or",
    "type": "string"
    },
    "rangeitems": {
    "description": "List of range item",
    "items": {
    "$ref": "#/$defs/rangeitem"
    },
    "type": "array"
    },
    "type": {
    "const": "diagonal",
    "description": "Type of the filter",
    "type": "string"
    },
    "version": {
    "description": "Define the version of the object",
    "example": 1,
    "type": "integer"
    }
    },
    "required": [
    "type",
    "operator",
    "enabled",
    "inverted",
    "rangeitems",
    "id"
    ],
    "title": "Filter diagonal definition",
    "type": "object"
    },
    "filter": {
    "oneOf": [
    {
    "$ref": "#/$defs/box"
    },
    {
    "$ref": "#/$defs/all"
    },
    {
    "$ref": "#/$defs/attribute"
    },
    {
    "$ref": "#/$defs/boolean"
    },
    {
    "$ref": "#/$defs/literal"
    },
    {
    "$ref": "#/$defs/compound"
    },
    {
    "$ref": "#/$defs/diagonal"
    },
    {
    "$ref": "#/$defs/hasfield"
    },
    {
    "$ref": "#/$defs/partinstanceidlist"
    },
    {
    "$ref": "#/$defs/range"
    },
    {
    "$ref": "#/$defs/filterset"
    }
    ]
    },
    "filterset": {
    "additionalProperties": false,
    "properties": {
    "enabled": {
    "default": true,
    "description": "If disabled, this filter is completely ignored during all the computations",
    "example": true,
    "type": "boolean"
    },
    "id": {
    "description": "an object id : only ascii non control and non blank characters",
    "example": "123e4567e89b12d3a456426614174000",
    "maxLength": 64,
    "pattern": "^[\\x21-\\x7E]{1,64}$",
    "type": "string"
    },
    "inverted": {
    "description": "When 'inverted', a filter elects all the `part instances` that would not be selected if it was not inverted.",
    "example": true,
    "type": "boolean"
    },
    "operator": {
    "default": "and",
    "description": "Operator to apply with this filter and its closest enabled predecessor in its parent container.",
    "enum": [
    "or",
    "and",
    "minus"
    ],
    "example": "or",
    "type": "string"
    },
    "subfilters": {
    "description": "List of sub filters",
    "items": {
    "oneOf": [
    {
    "$ref": "#/$defs/box"
    },
    {
    "$ref": "#/$defs/all"
    },
    {
    "$ref": "#/$defs/attribute"
    },
    {
    "$ref": "#/$defs/boolean"
    },
    {
    "$ref": "#/$defs/literal"
    },
    {
    "$ref": "#/$defs/compound"
    },
    {
    "$ref": "#/$defs/diagonal"
    },
    {
    "$ref": "#/$defs/hasfield"
    },
    {
    "$ref": "#/$defs/partinstanceidlist"
    },
    {
    "$ref": "#/$defs/range"
    },
    {
    "$ref": "#/$defs/filterset"
    }
    ]
    },
    "type": "array"
    },
    "type": {
    "const": "set",
    "description": "Type of the filter",
    "type": "string"
    },
    "version": {
    "description": "Define the version of the object",
    "example": 1,
    "type": "integer"
    }
    },
    "required": [
    "type",
    "enabled",
    "operator",
    "inverted",
    "subfilters",
    "id"
    ],
    "title": "Filter set definition",
    "type": "object"
    },
    "hasfield": {
    "additionalProperties": false,
    "properties": {
    "attribute": {
    "description": "Name of the attribute to filter with",
    "example": "PartNumber",
    "minLength": 0,
    "type": "string"
    },
    "enabled": {
    "default": true,
    "description": "If disabled, this filter is completely ignored during all the computations",
    "example": true,
    "type": "boolean"
    },
    "id": {
    "description": "an object id : only ascii non control and non blank characters",
    "example": "123e4567e89b12d3a456426614174000",
    "maxLength": 64,
    "pattern": "^[\\x21-\\x7E]{1,64}$",
    "type": "string"
    },
    "inverted": {
    "description": "When 'inverted', a filter elects all the `part instances` that would not be selected if it was not inverted.",
    "example": true,
    "type": "boolean"
    },
    "operator": {
    "default": "and",
    "description": "Operator to apply with this filter and its closest enabled predecessor in its parent container.",
    "enum": [
    "or",
    "and",
    "minus"
    ],
    "example": "or",
    "type": "string"
    },
    "type": {
    "const": "hasfield",
    "description": "Type of the filter",
    "type": "string"
    },
    "version": {
    "description": "Define the version of the object",
    "example": 1,
    "type": "integer"
    }
    },
    "required": [
    "type",
    "operator",
    "enabled",
    "inverted",
    "attribute",
    "id"
    ],
    "title": "Filter Has field definition",
    "type": "object"
    },
    "literal": {
    "additionalProperties": false,
    "properties": {
    "enabled": {
    "default": true,
    "description": "If disabled, this filter is completely ignored during all the computations",
    "example": true,
    "type": "boolean"
    },
    "id": {
    "description": "an object id : only ascii non control and non blank characters",
    "example": "123e4567e89b12d3a456426614174000",
    "maxLength": 64,
    "pattern": "^[\\x21-\\x7E]{1,64}$",
    "type": "string"
    },
    "inverted": {
    "description": "When 'inverted', a filter elects all the `part instances` that would not be selected if it was not inverted.",
    "example": true,
    "type": "boolean"
    },
    "operator": {
    "default": "and",
    "description": "Operator to apply with this filter and its closest enabled predecessor in its parent container.",
    "enum": [
    "or",
    "and",
    "minus"
    ],
    "example": "or",
    "type": "string"
    },
    "query": {
    "description": "Sets the query string in the 3djuump infinite literal and search query language",
    "example": ":PartNumber=='bolt'",
    "type": "string"
    },
    "type": {
    "const": "literal",
    "description": "Type of the filter",
    "type": "string"
    },
    "version": {
    "description": "Define the version of the object",
    "example": 1,
    "type": "integer"
    }
    },
    "required": [
    "type",
    "operator",
    "enabled",
    "inverted",
    "query",
    "id"
    ],
    "title": "Filter literal definition",
    "type": "object"
    },
    "partinstanceidlist": {
    "additionalProperties": false,
    "properties": {
    "buildid": {
    "description": "Id of the build use to create the part list instance",
    "type": "string"
    },
    "enabled": {
    "default": true,
    "description": "If disabled, this filter is completely ignored during all the computations",
    "example": true,
    "type": "boolean"
    },
    "id": {
    "description": "an object id : only ascii non control and non blank characters",
    "example": "123e4567e89b12d3a456426614174000",
    "maxLength": 64,
    "pattern": "^[\\x21-\\x7E]{1,64}$",
    "type": "string"
    },
    "inverted": {
    "description": "When 'inverted', a filter elects all the `part instances` that would not be selected if it was not inverted.",
    "example": true,
    "type": "boolean"
    },
    "list": {
    "description": "List of part instance ids",
    "items": {
    "type": "number"
    },
    "type": "array"
    },
    "operator": {
    "default": "and",
    "description": "Operator to apply with this filter and its closest enabled predecessor in its parent container.",
    "enum": [
    "or",
    "and",
    "minus"
    ],
    "example": "or",
    "type": "string"
    },
    "type": {
    "const": "partinstanceidlist",
    "description": "Type of the filter",
    "type": "string"
    },
    "version": {
    "description": "Define the version of the object",
    "example": 1,
    "type": "integer"
    }
    },
    "required": [
    "type",
    "operator",
    "enabled",
    "inverted",
    "buildid",
    "list",
    "id"
    ],
    "title": "Filter Part instance list definition",
    "type": "object"
    },
    "range": {
    "additionalProperties": false,
    "properties": {
    "attribute": {
    "description": "Name of the attribute to filter with",
    "example": "PartNumber",
    "minLength": 0,
    "type": "string"
    },
    "enabled": {
    "default": true,
    "description": "If disabled, this filter is completely ignored during all the computations",
    "example": true,
    "type": "boolean"
    },
    "id": {
    "description": "an object id : only ascii non control and non blank characters",
    "example": "123e4567e89b12d3a456426614174000",
    "maxLength": 64,
    "pattern": "^[\\x21-\\x7E]{1,64}$",
    "type": "string"
    },
    "inverted": {
    "description": "When 'inverted', a filter elects all the `part instances` that would not be selected if it was not inverted.",
    "example": true,
    "type": "boolean"
    },
    "operator": {
    "default": "and",
    "description": "Operator to apply with this filter and its closest enabled predecessor in its parent container.",
    "enum": [
    "or",
    "and",
    "minus"
    ],
    "example": "or",
    "type": "string"
    },
    "rangeitems": {
    "description": "List of range item",
    "items": {
    "$ref": "#/$defs/rangeitem"
    },
    "type": "array"
    },
    "type": {
    "const": "range",
    "description": "Type of the filter",
    "type": "string"
    },
    "version": {
    "description": "Define the version of the object",
    "example": 1,
    "type": "integer"
    }
    },
    "required": [
    "type",
    "operator",
    "enabled",
    "inverted",
    "attribute",
    "rangeitems",
    "id"
    ],
    "title": "Filter range definition",
    "type": "object"
    },
    "rangeitem": {
    "additionalProperties": false,
    "properties": {
    "includedLower": {
    "description": "Sets if the lower bound value should be included or excluded",
    "type": "boolean"
    },
    "includedUpper": {
    "description": "Sets if the upper bound value should be included or excluded",
    "type": "boolean"
    },
    "lower": {
    "description": "Lower bound of the range item",
    "type": "number"
    },
    "upper": {
    "description": "Upper bound of the range item",
    "type": "number"
    }
    },
    "required": [
    "includedLower",
    "includedUpper"
    ],
    "title": "Range item definition",
    "type": "object"
    },
    "retrievalType": {
    "enum": [
    "none",
    "geometric_instance_ids",
    "geometric_and_part_instance_ids"
    ],
    "type": "string"
    },
    "workingset": {
    "additionalProperties": false,
    "properties": {
    "behavior": {
    "description": "The way data is computed inside the working set",
    "type": "integer"
    },
    "configurationids": {
    "items": {
    "description": "ID of a JSON document",
    "maxLength": 255,
    "minLength": 1,
    "pattern": "^[^_].{0,255}$",
    "type": "string"
    },
    "type": "array"
    },
    "dependencies": {
    "items": {
    "$ref": "#/$defs/dependencyItem"
    },
    "type": "array"
    },
    "enabled": {
    "type": "boolean"
    },
    "filters": {
    "description": "List of sub filters",
    "items": {
    "$ref": "#/$defs/filter"
    },
    "type": "array"
    },
    "id": {
    "description": "an object id : only ascii non control and non blank characters",
    "example": "123e4567e89b12d3a456426614174000",
    "maxLength": 64,
    "pattern": "^[\\x21-\\x7E]{1,64}$",
    "type": "string"
    },
    "retrieval": {
    "$ref": "#/$defs/retrievalType"
    },
    "type": {
    "const": "workingset",
    "type": "string"
    },
    "version": {
    "description": "Define the version of the object",
    "example": 1,
    "type": "integer"
    }
    },
    "required": [
    "id",
    "type",
    "filters",
    "dependencies",
    "enabled",
    "retrieval",
    "configurationids",
    "behavior"
    ],
    "title": "WorkingSet definition",
    "type": "object"
    }
    },
    "$ref": "#/$defs/datasessioncontext",
    "$schema": "https://json-schema.org/draft-07/schema#"
    }

    This schema may evolve in the future.

    Parameters

    • pAllData: string | Object
      in
      Internal DataSessionInterface data to set.

    Returns boolean

    true if the data is set.

    See

    toJSON

  • Gets the list of available annotation types.

    Please see Annotations for more explanations about annotations.

    Modifying this array in place results in undefined behavior.

    DO NOT modify this array.

    Returns string[]

    const
    The list of annotation types.
  • Gets the list of bound InfiniteEngineInterface from this DataSessionInterface.

    Parameters

    Returns boolean

    true if the call succeeded.

  • Gets the build id of the loaded/loading data session.

    Returns string

    The build id used by the Infinite backend.

  • Gets the list of configurations.

    Please see configurations for more explanations about configurations.

    Modifying this array in place results in undefined behavior.

    DO NOT modify this array.

    Returns ConfigurationInterface[]

    const
    The list of configurations.
  • Gets the data session token that may be used in other requests to prove the authentication to the 3djuump Infinite architecture.

    Any http request should have the header x-infinite-bearer : <DataSessionInterface.getDataSessionBearer()>. If the data session is not connected, returns an empty string.

    Returns string

    The data session token used to prove the authentication.

  • Gets the data session id used by the Infinite backend.

    This value may be used to call directly some backend services.

    Returns string

    The data session id used by the Infinite backend.

  • Gets the Axis Aligned Bounding Box of the currently loaded DMU.

    Returns false if no DMU is loaded (DataSessionInterfaceSignal.DMULoadingSuccess).

    Parameters

    • pDmuAABBOut: AABB
      out
      AABB of the DMU.

    Returns boolean

    true if a DMU is loaded and pDmuAABBOut is updated.

  • Gets the extended data session token that may be used in other requests to prove the authentication to the 3djuump Infinite architecture.

    The extended bearer is heavier than getDataSessionBearer and is available only if the directory session was connected with an extended bearer request (Please refer to DirectorySessionInterface.getSamePageAuthenticationUrl and DirectorySessionInterface.getPopupBasedAuthenticationUrl).

    Any http request may have the header x-infinite-bearer : <DataSessionInterface.getExtendedDataSessionBearer()>. If the data session is not connected, returns an empty string.

    Returns string

    The extended data session token used to prove the authentication.

  • Gets the axis aligned bounding box of the given geometric instance id.

    Call this function after the DMU has been loaded (DataSessionInterfaceSignal.DMULoadingSuccess) with a previously created AABB.

    Returns true if the given geometric instance id is valid.

    Parameters

    • pGeometricInstanceId: number
      in
      The geometric instance id to query.
    • pAABBOut: AABB
      out
      The resulting AABB of the geometric instance.

    Returns boolean

    true if pAABBOut is updated.

  • Gets the diagonal squared length of the Oriented Bounding Box (OBB) of the given geometric instance id.

    Returns -1 if pGeometricInstanceId is an invalid geometric instance id, or the diagonal squared length of the OBB if it is valid.

    Parameters

    • pGeometricInstanceId: number
      in
      The geometric instance id to query.

    Returns number

    The diagonal squared length of the OBB of the geometric instance or -1 if invalid.

  • Gets the maximum diagonal squared length of all the Oriented Bounding Box (OBB) of all the geometric instances.

    Returns the maximum diagonal squared length of the current DMU, or -1 if a DMU has not been loaded (DataSessionInterfaceSignal.DMULoadingSuccess).

    Returns number

    The maximum diagonal squared length of the current DMU, or -1 if no DMU is loaded.

  • Gets the minimum diagonal squared length of all the Oriented Bounding Box (OBB) of all the geometric instances.

    Returns the minimum diagonal squared length of the current DMU, or -1 if a DMU has not been loaded ().

    Returns number

    The minimum diagonal squared length of the current DMU, or -1 if no DMU is loaded.

  • Gets the granted scopes that have been granted while opening the build.

    The user may have requested a set of scopes when calling openDataSession, but some requested scopes may not be granted (perhaps they were not available to the user). This call tells the scopes that have been granted when the build have been opened.

    Parameters

    Returns void

  • Gets the security tags used that have been granted while opening the build.

    The user may have requested a set of tags when calling openDataSession, but some requested restriction tags may not be granted (perhaps they were not part of the given build, etc ...). This call tells the extra tags that have been granted when the build have been opened.

    Parameters

    • pTags: string[]
      out
      the granted security tags when opening the build.

    Returns void

  • Gets the maximum geometric instance id of the DMU.

    Valid geometric instance ids range from 1 to getMaximumGeometricId() included. Please refer to Main ID Types for more information.

    Returns the maximum geometric instance id if a DMU is loaded (DataSessionInterfaceSignal.DMULoadingSuccess, 0 else.

    Returns number

    The maximum geometric instance id, 0 if no DMU is loaded.

  • Gets the progress on the openDataSession call.

    Such a progress is a float value between 0 and 1. 1 is returned when the open procedure is over.

    Returns number

    The progress of the openDataSession procedure.

  • Gets the original matrix of the given geometric instance id, independently to any transformation that may be applied to the given geometry.

    Call this function after the DMU has been loaded (DataSessionInterfaceSignal.DMULoadingSuccess) with a previously created AABB.

    Returns true if the given geometric instance id is valid.

    Parameters

    • pGeometricInstanceId: number
      in
      The geometric instance id to query.
    • pMatrixOut: Matrix4
      out
      The resulting Matrix of the geometric instance.

    Returns boolean

    true if pMatrixOut is updated.

  • Gets a project document by its id.

    Available project documents are :

    • com.3djuump:defaultsettings (field of view, orientation, etc).
    • com.3djuump:indexinfo (elasticsearch index information) : this information is accessible through the AttributesDictionaryInterface.

    Please refer to the integration manual to have more information about these documents.

    It is very unlikely any developer will use these versioned documents.

    Example (illustration purpose only):

    const lDocs = [
    {
    "id": "com.3djuump:defaultsettings",
    "profiles": [],
    "settings": {
    "backfaceculling": false,
    "dynamiclowdefprofiles": {
    "high": 2097152,
    "standard": 1048576
    },
    "fieldofview": {
    "degree": 25,
    "orientation": "vertical"
    },
    "frameorientation": {
    "dir": [
    -1,
    0,
    0
    ],
    "up": [
    0,
    0,
    1
    ]
    }
    },
    "subtype": "defaultsettings",
    "tasksettings": {
    "PresentationTask": {
    "aspectratio": [
    16,
    9
    ]
    }
    },
    "ts": 1591950944,
    "type": "projectdocument",
    "version": "8.0"
    },
    {
    "id": "com.3djuump:indexinfo",
    "internal": {
    "effectivity": {
    "SB": {
    "nested": [
    "effectivity"
    ],
    "type": "keyword",
    "values": [
    "SB1",
    "not_SB1"
    ]
    },
    "engine": {
    "nested": [
    "effectivity"
    ],
    "type": "keyword",
    "values": [
    "A",
    "B"
    ]
    }
    },
    "metadata": {
    "system": {
    "type": "text",
    "values": [
    "Structure",
    "Interior",
    "Exterior",
    "windows",
    "Wheel base"
    ]
    },
    "test.nested.text": {
    "nested": [
    "metadata",
    "test",
    "nested"
    ],
    "type": "text",
    "values": [
    "A",
    "B",
    "C"
    ]
    },
    "test.bool": {
    "type": "boolean"
    },
    "test.date": {
    "max": 1528114033000,
    "min": 1528114033000,
    "type": "date"
    },
    "test.date_range": {
    "type": "date_range"
    },
    "test.double_range": {
    "type": "double_range"
    },
    "test.int": {
    "max": 1,
    "min": 1,
    "type": "double"
    }
    }
    },
    "seq": 814,
    "subtype": "indexinfo",
    "type": "indexdocument",
    "version": 1
    },
    {
    "id": "com.3djuump:scripts",
    "scriptbase64": "base64 string",
    "subtype": "scripts",
    "taskscripts": {
    "AnnotationTask": "base64 string"
    },
    "ts": 1598877573,
    "type": "projectdocument",
    "version": "8.0"
    }
    ];

    These documents are json documents.

    Returns the json document as a string if the given document is available in the 3djuump Infinite project.

    Parameters

    • pDocumentId: string
      in
      The project document id to fetch.

    Returns string

    The document as a string, or undefined if the document could not be found or the DMU is not loaded.

  • Gets the URL of the web API proxy this data session is connected to.

    Returns string

    The URL of the chosen proxy.

  • Gets the source model id of the given geometric instance id.

    2 geometric instance ids with the same source model id means the 2 instances have the same geometric representation, but with different matrices.

    A valid source model id is a strictly positive integer. Returns 0 in case of error (invalid geometric instance id).

    Parameters

    • pGeometricInstanceId: number
      in
      The geometric instance id to query.

    Returns number

    The source model id of the geometric instance.

  • Computes the axis aligned bounding box of the given geometric instances.

    This consists in the union of all the AABB of the geometric instances expressed by their geometric instance ids.

    Call this function once the DMU has been loaded (DataSessionInterfaceSignal.DMULoadingSuccess) with a previously created AABB.

    Returns true if at least one geometric instance id inside pGeometricInstanceIds is valid. Invalid geometric instance ids are silently discarded.

    Parameters

    • pGeometricInstanceIds: number[] | Uint32Array
      in
      the list of geometric instance ids to query.
    • pAABBOut: AABB
      out
      the union of all the AABB o the geometric instance.

    Returns boolean

    true if at least one geometric instance id inside pGeometricInstanceIds is valid and pAABBOut is therefore updated.

  • Tells if the EventDispatcher has such a callback registered for the given event type.

    Parameters

    • pType: string
      in
      The type of the event to test.
    • pListener: tListenerCallback
      in
      The listener function that gets tested.

    Returns boolean

    true if such a listener is installed for the given type of event.

  • Tells if the EventDispatcher has such a callback registered for the given callback id.

    Parameters

    • pId: string
      in
      The id of the callback to test.

    Returns boolean

    true if such a listener is installed for the given callback id.

  • Tells if the DMU has features.

    Features are lines and circles that are detected on the 3D data.

    Prior to the infinite architecture 4.1 version, features did not exist. As such, any DMU migrated from versions prior to the 4.1 version will not have any feature. DMU created after (or equal) the 4.1 versions have the feature detection algorithm running.

    Calling this function before receiving DataSessionInterfaceSignal.DMULoadingSuccess event will return false.

    Returns boolean

    true if the currently loaded DMU has features.

  • Tells if the DataSessionInterface is configured as "Primary" session behavior.

    The DataSessionInterface is by default configured as "Primary".

    The primary session behavior consists in querying the bearers (getDataSessionBearer, getExtendedDataSessionBearer) regularly while a secondary DataSessionInterface should receive the new bearers with setTokenValues. This primary/secondary session mechanism allows to use multiple data sessions objects that share the same data session on the server. This may be useful to share the same data session upon multiple tabs of the browser.

    Returns boolean

    true if the DataSessionInterface is configured as a primary session behavior.

  • Starts the open data session procedure.

    A connection is established between the client and the 3djuump Infinite proxy. Security tokens are exchanged and initialization data is retrieved from the proxy and the cache if relevant. This operation may take from a few seconds to several minutes depending on the size of the data to work with.

    When data is ready, the DataSessionInterfaceSignal.DMULoadingSuccess signal is sent.

    If an error occurs, then the DataSessionInterfaceSignal.DMULoadingFailed signal is sent.

    Additional functionalities may be required with pAddedScopes. When opening a data session, the user may request the rights to :

    • Download evojuump files.
    • Export 2d files.
    • Export 3d files. Granted scopes are available with getGrantedScopes.

    pRestrictionTags should not contain duplicates.

    Parameters

    • Optional pRestrictionTags: string[]
      in
      If set, the data session will be opened with less security tags the user is allowed to use. An intersection with the user security tags, the build security tags and pRestrictionTags is done, and the resulting security tags are used to open the 3djuump build.
    • Optional pAddedScopes: DataSessionInterfaceScopes[]
      in
      If set, the data session wil be open with available added functionalities (DataSessionInterfaceScopes).

    Returns boolean

    true if the data session open procedure can be started. Returns false in case the DataSessionInterface has already been opened.

  • Opens a DataSessionInterface in secondary session mode.

    Once a DataSessionInterface has been fully loaded with openDataSession, a secondary DataSessionInterface may be open with openSecondaryDataSession with the result of requestNewSecondaryDataSession called on the primary DataSessionInterface.

    /** 
    * Sample to illustrate the use of the primary/secondary session mechanism of DirectorySessionInterface and DataSessionInterface.
    */
    import {
    InfiniteCacheFactory, DirectorySessionFactory,
    InfiniteCacheInterface, DirectorySessionInterface,
    DataSessionInterface,
    DataSessionInterfaceSignal, DirectorySessionInterfaceSignal,
    SecondaryDirectorySessionInterfaceInfo,
    SecondaryDataSessionInterfaceInfo,
    AuthenticationGetURLResult,
    } from 'generated_files/documentation/appinfiniteapi';

    // this sample holds the code to be use in the primary tab (primaryCode)
    // and in the secondary tab (secondaryCode)

    // a callback to receive messages
    type tMessageHandler = (pMessage: any) => void;

    // we suppose that there exists a message system
    let sendMessage : (pMessage: any) => void;

    // we suppose that we can register a handler to receive messages
    let registerMessageHandler : (pMessageHandler: tMessageHandler) => void;

    // the primary code
    const primaryCode = () : void =>
    {
    // created previously
    // this is the directory session that will server as primary session
    // this DirectorySessionInterface should already be logged in
    let lOriginalDirectorySession : DirectorySessionInterface;

    // created previously
    // this is the data session that will server as primary session
    // this DataSessionInterface should already be primary session
    let lOriginalDataSession : DataSessionInterface;

    // create a secondary session info to init the future secondary DirectorySessionInterface
    const lSecondaryDirectorySessionInfo : SecondaryDirectorySessionInterfaceInfo | undefined = lOriginalDirectorySession.requestNewSecondaryDirectorySession();
    if(lSecondaryDirectorySessionInfo === undefined)
    {
    // output some fancy error message
    console.error('secondary directory session info creation failed');
    return;
    }

    // create a secondary session info to init the future secondary DataSessionInterface
    // warning : this call will hold resources in the primary DataSessionInterface
    // when the secondary data session is no longer useful
    // release resources with unregisterSecondaryDataSession
    // warning: there is a finite number of secondary data sessions that may be created
    let lSecondaryDataSessionInfo : SecondaryDataSessionInterfaceInfo | undefined = lOriginalDataSession.requestNewSecondaryDataSession();
    if(lSecondaryDataSessionInfo === undefined)
    {
    // output some fancy error message
    console.error('secondary data session info creation failed');
    return;
    }

    // called when the DirectorySessionInterface updates its tokens
    const lDirectorySessionTokenUpdate = () : void => {
    const lHttpBearer : string = lOriginalDirectorySession.getHttpBearer();
    // only update tokens when the directory session is connected
    if(lHttpBearer.length > 0)
    {
    // send the new directory session tokens to the secondary
    sendMessage({
    type: 'directorySessionTokens',
    httpBearer: lHttpBearer,
    authenticationBearer: lOriginalDirectorySession.getAuthenticationBearer(),
    extendedAuthenticationBearer: lOriginalDirectorySession.getExtendedAuthenticationBearer(),
    });
    }
    };

    // called when the DataSessionInterface updates its tokens
    const lDataSessionTokenUpdate = () : void => {
    const lDataSessionBearer : string = lOriginalDataSession.getDataSessionBearer();
    // only update tokens when the data session is connected
    if(lDataSessionBearer.length > 0)
    {
    // send the new data session tokens to the secondary session
    sendMessage({
    type: 'dataSessionTokens',
    dataSessionBearer: lDataSessionBearer,
    extendedDataSessionBearer: lOriginalDataSession.getExtendedDataSessionBearer(),
    });
    }
    };

    // message callback, receive messages from the secondary session
    const onMessage : tMessageHandler = (pMessage : any) : void =>
    {
    switch(pMessage.type)
    {
    // cleanup the secondary session resources
    case 'dataSessionCleanup':
    if(lSecondaryDataSessionInfo !== undefined)
    {
    lOriginalDataSession.unregisterSecondaryDataSession(lSecondaryDataSessionInfo);
    // cleanup only once
    lSecondaryDataSessionInfo = undefined;
    }
    break;
    default:
    // this should not happen, we have no other message types that we may receive
    console.error('Unexpected message type');
    break;
    }
    };

    // and register the token update functions on token update
    lOriginalDirectorySession.addEventListener(DirectorySessionInterfaceSignal.TokenUpdated, lDirectorySessionTokenUpdate);
    lOriginalDataSession.addEventListener(DataSessionInterfaceSignal.TokenUpdated, lDataSessionTokenUpdate);
    // register callbacks
    registerMessageHandler(onMessage);

    // we are ready, send the infos to load a new secondary directory and data session
    sendMessage({
    type: 'init',
    directorySession: lSecondaryDirectorySessionInfo,
    dataSession: lSecondaryDataSessionInfo,
    // build id is required to create a data session on the correct build
    buildId: lOriginalDataSession.getBuildId()
    });
    };

    // the secondary session code
    const secondaryCode = () : void =>
    {
    // create a directory session
    const sDirectoryUrl : string = 'https://my_directory:443/directory';
    // before connection, this is a "normal" one
    const lSecondaryDirectorySession : DirectorySessionInterface = DirectorySessionFactory.CreateDirectorySession(sDirectoryUrl);
    // Create a cache to avoid requesting heavy data from the server if data has been retrieved already
    const lCache: InfiniteCacheInterface = InfiniteCacheFactory.CreateInfiniteCache();
    // the new data session
    // we cannot create it right now, we must wait for secondary session info and directory session login
    let lSecondaryDataSession : DataSessionInterface;
    // hold the open secondary session info for future call
    let lSecondaryDataSessionInterfaceInfo : SecondaryDataSessionInterfaceInfo;
    // the build id we will be connected to
    let lDataSessionBuildId : string = '';

    // Success callback on DirectorySessionInterface login
    const onLoginSuccess = () : void => {
    // weird, we should have a build id at this time
    if(lDataSessionBuildId.length === 0)
    {
    // and output some message if the data session creation failed
    console.error('data session creation failed, empty build id');
    // and tell the primary session to get rid of the secondary session
    sendMessage({ type: 'dataSessionCleanup' });
    return;
    }
    // actually create the DataSessionInterface
    lSecondaryDataSession = lSecondaryDirectorySession.createDataSession(lDataSessionBuildId, lCache);
    if(lSecondaryDataSession === undefined)
    {
    // and output some message if the data session creation failed
    console.error('data session creation failed');
    // and tell the primary session to get rid of the secondary session
    sendMessage({ type: 'dataSessionCleanup' });
    return;
    }
    // open it in secondary session mode
    if(!lSecondaryDataSession.openSecondaryDataSession(lSecondaryDataSessionInterfaceInfo))
    {
    // and output some message if the data session opening failed
    console.error('secondary data session opening failed');
    // get rid of data
    lSecondaryDataSession.dispose();
    lSecondaryDataSession = undefined;
    // and tell the primary session to get rid of the secondary session
    sendMessage({ type: 'dataSessionCleanup' });
    }
    // and then we must wait for the DataSessionInterface to be connected
    };

    // message callback, receive secondary sessions info and tokens
    const onMessage : tMessageHandler = (pMessage : any) : void =>
    {
    switch(pMessage.type)
    {
    // secondary sessions infos
    case 'init':
    {
    lSecondaryDataSessionInterfaceInfo = pMessage.dataSession;
    lDataSessionBuildId = pMessage.buildId;
    const lResult : AuthenticationGetURLResult = lSecondaryDirectorySession.openSecondaryDirectorySession(pMessage.directorySession);
    if(lResult !== AuthenticationGetURLResult.AuthenticationPending)
    {
    // and output some message if the data session opening failed
    console.error('directory session opening failed');
    // and tell the primary session to get rid of the secondary session
    sendMessage({ type: 'dataSessionCleanup' });
    }
    break;
    }
    case 'directorySessionTokens':
    {
    // do nothing if the directory session is not connected
    if(!lSecondaryDirectorySession.isAuthenticated())
    {
    return;
    }
    // and update the tokens
    const lResult : boolean = lSecondaryDirectorySession.setTokenValues(pMessage.httpBearer, pMessage.authenticationBearer, pMessage.extendedAuthenticationBearer);
    if(!lResult)
    {
    // and output some message if the token update failed
    console.error('set token values failed');
    // and tell the primary session to get rid of the secondary session
    sendMessage({ type: 'dataSessionCleanup' });
    }
    break;
    }
    case 'dataSessionTokens':
    {
    // do nothing if the data session is not connected nor created
    if(lSecondaryDataSession === undefined || !lSecondaryDataSession.isConnected())
    {
    return;
    }
    // and update the tokens
    const lResult : boolean = lSecondaryDataSession.setTokenValues(pMessage.dataSessionBearer, pMessage.extendedDataSessionBearer);
    if(!lResult)
    {
    // and output some message if the token update failed
    console.error('set token values failed');
    // and tell the primary session to get rid of the secondary session
    sendMessage({ type: 'dataSessionCleanup' });
    }
    break;
    }
    default:
    // this should not happen, we have no other message types that we may receive
    console.error('Unexpected message type');
    break;
    }
    };

    // register callbacks
    lSecondaryDirectorySession.addEventListener(DirectorySessionInterfaceSignal.LoginSuccess, onLoginSuccess);
    registerMessageHandler(onMessage);
    };

    // in the primary part
    primaryCode();

    // in the secondary part
    secondaryCode();

    Parameters

    Returns boolean

    true if the call succeeded.

  • Removes a listener from an event type.

    If no such listener is found, then the function returns false and does nothing. You must use the exact parameters that were used in addEventListener to actually remove the listener.

    Parameters

    • pType: string
      in
      The type of the listener that gets removed.
    • pListener: tListenerCallback

      The listener function that gets removed.

    • pObject: Object

      The listener object that was used when addEventListener was called.

    Returns boolean

    true if the callback was removed else false.

  • Removes a listener from an event type.

    If no such listener is found, then the function returns false and does nothing. You must use the exact parameters that were used in addEventListener to actually remove the listener.

    Parameters

    • pType: string
      in
      The type of the listener that gets removed.
    • pListener: tListenerCallback

      The listener function that gets removed.

    Returns boolean

    true if the callback was removed else false.

  • Removes a listener by its id.

    If no such listener is found, then the function returns false and does nothing. You must use the return value of addEventListener to actually remove the listener.

    Parameters

    • pId: string
      in
      The id returned by the call to addEventListener that you want to remove.

    Returns boolean

    true if the callback was removed else false.

  • Creates a SecondaryDataSessionInterfaceInfo in order to create a new secondary DataSessionInterface.

    Once called, the secondary DataSessionInterface will be considered open, and unregisterSecondaryDataSession must be called on the same object in order to reclaim the resources associated with the given secondary DataSessionInterface.

    This opaque object may be streamed to another tab (for example) and then used with openSecondaryDataSession and unregisterSecondaryDataSession. Please make sure openSecondaryDataSession will be used with the same buildid that was used to create the DataSessionInterface (DirectorySessionInterface.createDataSession).

    /** 
    * Sample to illustrate the use of the primary/secondary session mechanism of DirectorySessionInterface and DataSessionInterface.
    */
    import {
    InfiniteCacheFactory, DirectorySessionFactory,
    InfiniteCacheInterface, DirectorySessionInterface,
    DataSessionInterface,
    DataSessionInterfaceSignal, DirectorySessionInterfaceSignal,
    SecondaryDirectorySessionInterfaceInfo,
    SecondaryDataSessionInterfaceInfo,
    AuthenticationGetURLResult,
    } from 'generated_files/documentation/appinfiniteapi';

    // this sample holds the code to be use in the primary tab (primaryCode)
    // and in the secondary tab (secondaryCode)

    // a callback to receive messages
    type tMessageHandler = (pMessage: any) => void;

    // we suppose that there exists a message system
    let sendMessage : (pMessage: any) => void;

    // we suppose that we can register a handler to receive messages
    let registerMessageHandler : (pMessageHandler: tMessageHandler) => void;

    // the primary code
    const primaryCode = () : void =>
    {
    // created previously
    // this is the directory session that will server as primary session
    // this DirectorySessionInterface should already be logged in
    let lOriginalDirectorySession : DirectorySessionInterface;

    // created previously
    // this is the data session that will server as primary session
    // this DataSessionInterface should already be primary session
    let lOriginalDataSession : DataSessionInterface;

    // create a secondary session info to init the future secondary DirectorySessionInterface
    const lSecondaryDirectorySessionInfo : SecondaryDirectorySessionInterfaceInfo | undefined = lOriginalDirectorySession.requestNewSecondaryDirectorySession();
    if(lSecondaryDirectorySessionInfo === undefined)
    {
    // output some fancy error message
    console.error('secondary directory session info creation failed');
    return;
    }

    // create a secondary session info to init the future secondary DataSessionInterface
    // warning : this call will hold resources in the primary DataSessionInterface
    // when the secondary data session is no longer useful
    // release resources with unregisterSecondaryDataSession
    // warning: there is a finite number of secondary data sessions that may be created
    let lSecondaryDataSessionInfo : SecondaryDataSessionInterfaceInfo | undefined = lOriginalDataSession.requestNewSecondaryDataSession();
    if(lSecondaryDataSessionInfo === undefined)
    {
    // output some fancy error message
    console.error('secondary data session info creation failed');
    return;
    }

    // called when the DirectorySessionInterface updates its tokens
    const lDirectorySessionTokenUpdate = () : void => {
    const lHttpBearer : string = lOriginalDirectorySession.getHttpBearer();
    // only update tokens when the directory session is connected
    if(lHttpBearer.length > 0)
    {
    // send the new directory session tokens to the secondary
    sendMessage({
    type: 'directorySessionTokens',
    httpBearer: lHttpBearer,
    authenticationBearer: lOriginalDirectorySession.getAuthenticationBearer(),
    extendedAuthenticationBearer: lOriginalDirectorySession.getExtendedAuthenticationBearer(),
    });
    }
    };

    // called when the DataSessionInterface updates its tokens
    const lDataSessionTokenUpdate = () : void => {
    const lDataSessionBearer : string = lOriginalDataSession.getDataSessionBearer();
    // only update tokens when the data session is connected
    if(lDataSessionBearer.length > 0)
    {
    // send the new data session tokens to the secondary session
    sendMessage({
    type: 'dataSessionTokens',
    dataSessionBearer: lDataSessionBearer,
    extendedDataSessionBearer: lOriginalDataSession.getExtendedDataSessionBearer(),
    });
    }
    };

    // message callback, receive messages from the secondary session
    const onMessage : tMessageHandler = (pMessage : any) : void =>
    {
    switch(pMessage.type)
    {
    // cleanup the secondary session resources
    case 'dataSessionCleanup':
    if(lSecondaryDataSessionInfo !== undefined)
    {
    lOriginalDataSession.unregisterSecondaryDataSession(lSecondaryDataSessionInfo);
    // cleanup only once
    lSecondaryDataSessionInfo = undefined;
    }
    break;
    default:
    // this should not happen, we have no other message types that we may receive
    console.error('Unexpected message type');
    break;
    }
    };

    // and register the token update functions on token update
    lOriginalDirectorySession.addEventListener(DirectorySessionInterfaceSignal.TokenUpdated, lDirectorySessionTokenUpdate);
    lOriginalDataSession.addEventListener(DataSessionInterfaceSignal.TokenUpdated, lDataSessionTokenUpdate);
    // register callbacks
    registerMessageHandler(onMessage);

    // we are ready, send the infos to load a new secondary directory and data session
    sendMessage({
    type: 'init',
    directorySession: lSecondaryDirectorySessionInfo,
    dataSession: lSecondaryDataSessionInfo,
    // build id is required to create a data session on the correct build
    buildId: lOriginalDataSession.getBuildId()
    });
    };

    // the secondary session code
    const secondaryCode = () : void =>
    {
    // create a directory session
    const sDirectoryUrl : string = 'https://my_directory:443/directory';
    // before connection, this is a "normal" one
    const lSecondaryDirectorySession : DirectorySessionInterface = DirectorySessionFactory.CreateDirectorySession(sDirectoryUrl);
    // Create a cache to avoid requesting heavy data from the server if data has been retrieved already
    const lCache: InfiniteCacheInterface = InfiniteCacheFactory.CreateInfiniteCache();
    // the new data session
    // we cannot create it right now, we must wait for secondary session info and directory session login
    let lSecondaryDataSession : DataSessionInterface;
    // hold the open secondary session info for future call
    let lSecondaryDataSessionInterfaceInfo : SecondaryDataSessionInterfaceInfo;
    // the build id we will be connected to
    let lDataSessionBuildId : string = '';

    // Success callback on DirectorySessionInterface login
    const onLoginSuccess = () : void => {
    // weird, we should have a build id at this time
    if(lDataSessionBuildId.length === 0)
    {
    // and output some message if the data session creation failed
    console.error('data session creation failed, empty build id');
    // and tell the primary session to get rid of the secondary session
    sendMessage({ type: 'dataSessionCleanup' });
    return;
    }
    // actually create the DataSessionInterface
    lSecondaryDataSession = lSecondaryDirectorySession.createDataSession(lDataSessionBuildId, lCache);
    if(lSecondaryDataSession === undefined)
    {
    // and output some message if the data session creation failed
    console.error('data session creation failed');
    // and tell the primary session to get rid of the secondary session
    sendMessage({ type: 'dataSessionCleanup' });
    return;
    }
    // open it in secondary session mode
    if(!lSecondaryDataSession.openSecondaryDataSession(lSecondaryDataSessionInterfaceInfo))
    {
    // and output some message if the data session opening failed
    console.error('secondary data session opening failed');
    // get rid of data
    lSecondaryDataSession.dispose();
    lSecondaryDataSession = undefined;
    // and tell the primary session to get rid of the secondary session
    sendMessage({ type: 'dataSessionCleanup' });
    }
    // and then we must wait for the DataSessionInterface to be connected
    };

    // message callback, receive secondary sessions info and tokens
    const onMessage : tMessageHandler = (pMessage : any) : void =>
    {
    switch(pMessage.type)
    {
    // secondary sessions infos
    case 'init':
    {
    lSecondaryDataSessionInterfaceInfo = pMessage.dataSession;
    lDataSessionBuildId = pMessage.buildId;
    const lResult : AuthenticationGetURLResult = lSecondaryDirectorySession.openSecondaryDirectorySession(pMessage.directorySession);
    if(lResult !== AuthenticationGetURLResult.AuthenticationPending)
    {
    // and output some message if the data session opening failed
    console.error('directory session opening failed');
    // and tell the primary session to get rid of the secondary session
    sendMessage({ type: 'dataSessionCleanup' });
    }
    break;
    }
    case 'directorySessionTokens':
    {
    // do nothing if the directory session is not connected
    if(!lSecondaryDirectorySession.isAuthenticated())
    {
    return;
    }
    // and update the tokens
    const lResult : boolean = lSecondaryDirectorySession.setTokenValues(pMessage.httpBearer, pMessage.authenticationBearer, pMessage.extendedAuthenticationBearer);
    if(!lResult)
    {
    // and output some message if the token update failed
    console.error('set token values failed');
    // and tell the primary session to get rid of the secondary session
    sendMessage({ type: 'dataSessionCleanup' });
    }
    break;
    }
    case 'dataSessionTokens':
    {
    // do nothing if the data session is not connected nor created
    if(lSecondaryDataSession === undefined || !lSecondaryDataSession.isConnected())
    {
    return;
    }
    // and update the tokens
    const lResult : boolean = lSecondaryDataSession.setTokenValues(pMessage.dataSessionBearer, pMessage.extendedDataSessionBearer);
    if(!lResult)
    {
    // and output some message if the token update failed
    console.error('set token values failed');
    // and tell the primary session to get rid of the secondary session
    sendMessage({ type: 'dataSessionCleanup' });
    }
    break;
    }
    default:
    // this should not happen, we have no other message types that we may receive
    console.error('Unexpected message type');
    break;
    }
    };

    // register callbacks
    lSecondaryDirectorySession.addEventListener(DirectorySessionInterfaceSignal.LoginSuccess, onLoginSuccess);
    registerMessageHandler(onMessage);
    };

    // in the primary part
    primaryCode();

    // in the secondary part
    secondaryCode();

    or asynchronously :
    /** 
    * Sample to illustrate the asynchronous use of the primary/secondary session mechanism of DirectorySessionInterface
    * and DataSessionInterface.
    */
    import {
    InfiniteCacheFactory, DirectorySessionFactory,
    InfiniteCacheInterface, DirectorySessionInterface,
    DataSessionInterface,
    DataSessionInterfaceSignal, DirectorySessionInterfaceSignal,
    SecondaryDirectorySessionInterfaceInfo,
    SecondaryDataSessionInterfaceInfo,
    AsyncDirectorySessionWaitForLoadedResult,
    AsyncDirectorySessionWaitForLoadedResultReason,
    AsyncDataSessionInterfaceOpenResult,
    } from 'generated_files/documentation/appinfiniteapi';

    // this sample holds the code to be use in the primary tab (primaryCode)
    // and in the secondary tab (secondaryCode)

    // a callback to receive messages
    type tMessageHandler = (pMessage: any) => void;

    // we suppose that there exists a message system
    let sendMessage : (pMessage: any) => void;

    // we suppose that we can register a handler to receive messages
    let registerMessageHandler : (pMessageHandler: tMessageHandler) => void;

    // the primary code
    const primaryCode = () : void =>
    {
    // created previously
    // this is the directory session that will server as primary session
    // this DirectorySessionInterface should already be logged in
    let lOriginalDirectorySession : DirectorySessionInterface;

    // created previously
    // this is the data session that will server as primary session
    // this DataSessionInterface should already be connected
    let lOriginalDataSession : DataSessionInterface;

    // create a secondary session info to init the future secondary DirectorySessionInterface
    const lSecondaryDirectorySessionInfo : SecondaryDirectorySessionInterfaceInfo | undefined = lOriginalDirectorySession.requestNewSecondaryDirectorySession();
    if(lSecondaryDirectorySessionInfo === undefined)
    {
    // output some fancy error message
    console.error('secondary directory session info creation failed');
    return;
    }

    // create a secondary data session info to init the future secondary DataSessionInterface
    // warning : this call will hold resources in the primary DataSessionInterface
    // when the secondary data session is no longer useful
    // release resources with unregisterSecondaryDataSession
    // warning: there is a finite number of secondary data sessions that may be created
    let lSecondaryDataSessionInfo : SecondaryDataSessionInterfaceInfo | undefined = lOriginalDataSession.requestNewSecondaryDataSession();
    if(lSecondaryDataSessionInfo === undefined)
    {
    // output some fancy error message
    console.error('secondary data session info creation failed');
    return;
    }

    // called when the DirectorySessionInterface updates its tokens
    const lDirectorySessionTokenUpdate = () : void => {
    const lHttpBearer : string = lOriginalDirectorySession.getHttpBearer();
    // only update tokens when the directory session is connected
    if(lHttpBearer.length > 0)
    {
    // send the new directory session tokens to the secondary session
    sendMessage({
    type: 'directorySessionTokens',
    httpBearer: lHttpBearer,
    authenticationBearer: lOriginalDirectorySession.getAuthenticationBearer(),
    extendedAuthenticationBearer: lOriginalDirectorySession.getExtendedAuthenticationBearer(),
    });
    }
    };

    // called when the DataSessionInterface updates its tokens
    const lDataSessionTokenUpdate = () : void => {
    const lDataSessionBearer : string = lOriginalDataSession.getDataSessionBearer();
    // only update tokens when the data session is connected
    if(lDataSessionBearer.length > 0)
    {
    // send the new data session tokens to the secondary session
    sendMessage({
    type: 'dataSessionTokens',
    dataSessionBearer: lDataSessionBearer,
    extendedDataSessionBearer: lOriginalDataSession.getExtendedDataSessionBearer(),
    });
    }
    };

    // message callback, receive messages from the secondary session
    const onMessage : tMessageHandler = (pMessage : any) : void =>
    {
    switch(pMessage.type)
    {
    // cleanup the secondary data session resources
    case 'dataSessionCleanup':
    if(lSecondaryDataSessionInfo !== undefined)
    {
    lOriginalDataSession.unregisterSecondaryDataSession(lSecondaryDataSessionInfo);
    // cleanup only once
    lSecondaryDataSessionInfo = undefined;
    }
    break;
    default:
    // this should not happen, we have no other message types that we may receive
    console.error('Unexpected message type');
    break;
    }
    };

    // and register the token update functions on token update
    lOriginalDirectorySession.addEventListener(DirectorySessionInterfaceSignal.TokenUpdated, lDirectorySessionTokenUpdate);
    lOriginalDataSession.addEventListener(DataSessionInterfaceSignal.TokenUpdated, lDataSessionTokenUpdate);
    // register callbacks
    registerMessageHandler(onMessage);

    // we are ready, send the infos to load a new secondary directory and data session
    sendMessage({
    type: 'init',
    directorySession: lSecondaryDirectorySessionInfo,
    dataSession: lSecondaryDataSessionInfo,
    // build id is required to create a data session on the correct build
    buildId: lOriginalDataSession.getBuildId()
    });
    };

    // the secondary session code
    const secondaryCode = () : void =>
    {
    // create a directory session
    const sDirectoryUrl : string = 'https://my_directory:443/directory';
    // before connection, this is a "normal" one
    const lSecondaryDirectorySession : DirectorySessionInterface = DirectorySessionFactory.CreateDirectorySession(sDirectoryUrl);
    // Create a cache to avoid requesting heavy data from the server if data has been retrieved already
    const lCache: InfiniteCacheInterface = InfiniteCacheFactory.CreateInfiniteCache();
    // the new data session
    // we cannot create it right now, we must wait for secondary session info and directory session login
    let lSecondaryDataSession : DataSessionInterface;
    // hold the open secondary info for future call
    let lSecondaryDataSessionInterfaceInfo : SecondaryDataSessionInterfaceInfo;
    // the build id we will be connected to
    let lDataSessionBuildId : string = '';

    // message callback, receive secondary sessions info and tokens
    const onMessage : tMessageHandler = (pMessage : any) : void =>
    {
    switch(pMessage.type)
    {
    // secondary sessions infos
    case 'init':
    {
    lSecondaryDataSessionInterfaceInfo = pMessage.dataSession;
    lDataSessionBuildId = pMessage.buildId;
    lSecondaryDirectorySession.asyncOpenSecondaryDirectorySession(pMessage.directorySession).then(
    (pOpenResult: AsyncDirectorySessionWaitForLoadedResult) : void => {
    if(pOpenResult.reason !== AsyncDirectorySessionWaitForLoadedResultReason.OpenResult_LoginSuccess)
    {
    // and output some message if the data session opening failed
    console.error('directory session opening failed');
    // and tell the primary session to get rid of the secondary session
    sendMessage({ type: 'dataSessionCleanup' });
    return;
    }
    // weird, we should have a build id at this time
    if(lDataSessionBuildId.length === 0)
    {
    // and output some message if the data session creation failed
    console.error('data session creation failed, empty build id');
    // and tell the primary session to get rid of the secondary session
    sendMessage({ type: 'dataSessionCleanup' });
    return;
    }
    // actually create the DataSessionInterface
    lSecondaryDataSession = lSecondaryDirectorySession.createDataSession(lDataSessionBuildId, lCache);
    if(lSecondaryDataSession === undefined)
    {
    // and output some message if the data session creation failed
    console.error('data session creation failed');
    // and tell the primary session to get rid of the secondary session
    sendMessage({ type: 'dataSessionCleanup' });
    return;
    }
    // open it in secondary session mode
    lSecondaryDataSession.asyncOpenSecondaryDataSession(lSecondaryDataSessionInterfaceInfo).then(
    (pDataSessionResult: AsyncDataSessionInterfaceOpenResult) : void =>
    {
    if(pDataSessionResult !== AsyncDataSessionInterfaceOpenResult.OpenResult_Success)
    {
    // and output some message if the data session opening failed
    console.error('secondary data session opening failed');
    // get rid of data
    lSecondaryDataSession.dispose();
    lSecondaryDataSession = undefined;
    // and tell the primary session to get rid of the secondary session
    sendMessage({ type: 'dataSessionCleanup' });
    }
    // and do some fancy things there :)
    // we are connected correctly
    }
    );
    }
    );
    break;
    }
    case 'directorySessionTokens':
    {
    // do nothing if the directory session is not connected
    if(!lSecondaryDirectorySession.isAuthenticated())
    {
    return;
    }
    // and update the tokens
    const lResult : boolean = lSecondaryDirectorySession.setTokenValues(pMessage.httpBearer, pMessage.authenticationBearer, pMessage.extendedAuthenticationBearer);
    if(!lResult)
    {
    // and output some message if the token update failed
    console.error('set token values failed');
    // and tell the primary session to get rid of the secondary session
    sendMessage({ type: 'dataSessionCleanup' });
    }
    break;
    }
    case 'dataSessionTokens':
    {
    // do nothing if the data session is not connected nor created
    if(lSecondaryDataSession === undefined || !lSecondaryDataSession.isConnected())
    {
    return;
    }
    // and update the tokens
    const lResult : boolean = lSecondaryDataSession.setTokenValues(pMessage.dataSessionBearer, pMessage.extendedDataSessionBearer);
    if(!lResult)
    {
    // and output some message if the token update failed
    console.error('set token values failed');
    // and tell the primary session to get rid of the secondary session
    sendMessage({ type: 'dataSessionCleanup' });
    }
    break;
    }
    default:
    // this should not happen, we have no other message types that we may receive
    console.error('Unexpected message type');
    break;
    }
    };

    // register callbacks
    registerMessageHandler(onMessage);
    };

    // in the primary part
    primaryCode();

    // in the secondary part
    secondaryCode();

    The primary/secondary session mechanism may be used to share the same DataSessionInterface across multiple tabs.

    Returns SecondaryDataSessionInterfaceInfo

    A new SecondaryDataSessionInterfaceInfo if the call succeeded.

  • Relaunches the idle timer.

    For security reasons, the data session is closed when no event has been received for a long time, this duration depends on the server configuration. You may reset the idle timer at some time to avoid the user from being disconnected.

    When the user will be soon disconnected, then the DataSessionInterfaceSignal.IdleWarningDataSession signal is sent, if the user interacts with the system or restartIdleTimer is called, then the DataSessionReactivated signal is sent.
    If no user interaction takes place, then the data session is closed, the DataSessionInterfaceSignal.IdleDataSession signal is sent (no DataSessionInterfaceSignal.DataSessionClosed signal will be sent). You will have to call closeDataSession to clean up the resources.

    Returns void

  • Updates the bearers of a secondary DataSessionInterface on a regular basis.

    The primary DataSessionInterface that was used to call requestNewSecondaryDataSession must be monitored with the signal DataSessionInterfaceSignal.TokenUpdated and queried with getDataSessionBearer and getExtendedDataSessionBearer, and then the created secondary DataSessionInterface must be updated with setTokenValues.

    /** 
    * Sample to illustrate the use of the primary/secondary session mechanism of DirectorySessionInterface and DataSessionInterface.
    */
    import {
    InfiniteCacheFactory, DirectorySessionFactory,
    InfiniteCacheInterface, DirectorySessionInterface,
    DataSessionInterface,
    DataSessionInterfaceSignal, DirectorySessionInterfaceSignal,
    SecondaryDirectorySessionInterfaceInfo,
    SecondaryDataSessionInterfaceInfo,
    AuthenticationGetURLResult,
    } from 'generated_files/documentation/appinfiniteapi';

    // this sample holds the code to be use in the primary tab (primaryCode)
    // and in the secondary tab (secondaryCode)

    // a callback to receive messages
    type tMessageHandler = (pMessage: any) => void;

    // we suppose that there exists a message system
    let sendMessage : (pMessage: any) => void;

    // we suppose that we can register a handler to receive messages
    let registerMessageHandler : (pMessageHandler: tMessageHandler) => void;

    // the primary code
    const primaryCode = () : void =>
    {
    // created previously
    // this is the directory session that will server as primary session
    // this DirectorySessionInterface should already be logged in
    let lOriginalDirectorySession : DirectorySessionInterface;

    // created previously
    // this is the data session that will server as primary session
    // this DataSessionInterface should already be primary session
    let lOriginalDataSession : DataSessionInterface;

    // create a secondary session info to init the future secondary DirectorySessionInterface
    const lSecondaryDirectorySessionInfo : SecondaryDirectorySessionInterfaceInfo | undefined = lOriginalDirectorySession.requestNewSecondaryDirectorySession();
    if(lSecondaryDirectorySessionInfo === undefined)
    {
    // output some fancy error message
    console.error('secondary directory session info creation failed');
    return;
    }

    // create a secondary session info to init the future secondary DataSessionInterface
    // warning : this call will hold resources in the primary DataSessionInterface
    // when the secondary data session is no longer useful
    // release resources with unregisterSecondaryDataSession
    // warning: there is a finite number of secondary data sessions that may be created
    let lSecondaryDataSessionInfo : SecondaryDataSessionInterfaceInfo | undefined = lOriginalDataSession.requestNewSecondaryDataSession();
    if(lSecondaryDataSessionInfo === undefined)
    {
    // output some fancy error message
    console.error('secondary data session info creation failed');
    return;
    }

    // called when the DirectorySessionInterface updates its tokens
    const lDirectorySessionTokenUpdate = () : void => {
    const lHttpBearer : string = lOriginalDirectorySession.getHttpBearer();
    // only update tokens when the directory session is connected
    if(lHttpBearer.length > 0)
    {
    // send the new directory session tokens to the secondary
    sendMessage({
    type: 'directorySessionTokens',
    httpBearer: lHttpBearer,
    authenticationBearer: lOriginalDirectorySession.getAuthenticationBearer(),
    extendedAuthenticationBearer: lOriginalDirectorySession.getExtendedAuthenticationBearer(),
    });
    }
    };

    // called when the DataSessionInterface updates its tokens
    const lDataSessionTokenUpdate = () : void => {
    const lDataSessionBearer : string = lOriginalDataSession.getDataSessionBearer();
    // only update tokens when the data session is connected
    if(lDataSessionBearer.length > 0)
    {
    // send the new data session tokens to the secondary session
    sendMessage({
    type: 'dataSessionTokens',
    dataSessionBearer: lDataSessionBearer,
    extendedDataSessionBearer: lOriginalDataSession.getExtendedDataSessionBearer(),
    });
    }
    };

    // message callback, receive messages from the secondary session
    const onMessage : tMessageHandler = (pMessage : any) : void =>
    {
    switch(pMessage.type)
    {
    // cleanup the secondary session resources
    case 'dataSessionCleanup':
    if(lSecondaryDataSessionInfo !== undefined)
    {
    lOriginalDataSession.unregisterSecondaryDataSession(lSecondaryDataSessionInfo);
    // cleanup only once
    lSecondaryDataSessionInfo = undefined;
    }
    break;
    default:
    // this should not happen, we have no other message types that we may receive
    console.error('Unexpected message type');
    break;
    }
    };

    // and register the token update functions on token update
    lOriginalDirectorySession.addEventListener(DirectorySessionInterfaceSignal.TokenUpdated, lDirectorySessionTokenUpdate);
    lOriginalDataSession.addEventListener(DataSessionInterfaceSignal.TokenUpdated, lDataSessionTokenUpdate);
    // register callbacks
    registerMessageHandler(onMessage);

    // we are ready, send the infos to load a new secondary directory and data session
    sendMessage({
    type: 'init',
    directorySession: lSecondaryDirectorySessionInfo,
    dataSession: lSecondaryDataSessionInfo,
    // build id is required to create a data session on the correct build
    buildId: lOriginalDataSession.getBuildId()
    });
    };

    // the secondary session code
    const secondaryCode = () : void =>
    {
    // create a directory session
    const sDirectoryUrl : string = 'https://my_directory:443/directory';
    // before connection, this is a "normal" one
    const lSecondaryDirectorySession : DirectorySessionInterface = DirectorySessionFactory.CreateDirectorySession(sDirectoryUrl);
    // Create a cache to avoid requesting heavy data from the server if data has been retrieved already
    const lCache: InfiniteCacheInterface = InfiniteCacheFactory.CreateInfiniteCache();
    // the new data session
    // we cannot create it right now, we must wait for secondary session info and directory session login
    let lSecondaryDataSession : DataSessionInterface;
    // hold the open secondary session info for future call
    let lSecondaryDataSessionInterfaceInfo : SecondaryDataSessionInterfaceInfo;
    // the build id we will be connected to
    let lDataSessionBuildId : string = '';

    // Success callback on DirectorySessionInterface login
    const onLoginSuccess = () : void => {
    // weird, we should have a build id at this time
    if(lDataSessionBuildId.length === 0)
    {
    // and output some message if the data session creation failed
    console.error('data session creation failed, empty build id');
    // and tell the primary session to get rid of the secondary session
    sendMessage({ type: 'dataSessionCleanup' });
    return;
    }
    // actually create the DataSessionInterface
    lSecondaryDataSession = lSecondaryDirectorySession.createDataSession(lDataSessionBuildId, lCache);
    if(lSecondaryDataSession === undefined)
    {
    // and output some message if the data session creation failed
    console.error('data session creation failed');
    // and tell the primary session to get rid of the secondary session
    sendMessage({ type: 'dataSessionCleanup' });
    return;
    }
    // open it in secondary session mode
    if(!lSecondaryDataSession.openSecondaryDataSession(lSecondaryDataSessionInterfaceInfo))
    {
    // and output some message if the data session opening failed
    console.error('secondary data session opening failed');
    // get rid of data
    lSecondaryDataSession.dispose();
    lSecondaryDataSession = undefined;
    // and tell the primary session to get rid of the secondary session
    sendMessage({ type: 'dataSessionCleanup' });
    }
    // and then we must wait for the DataSessionInterface to be connected
    };

    // message callback, receive secondary sessions info and tokens
    const onMessage : tMessageHandler = (pMessage : any) : void =>
    {
    switch(pMessage.type)
    {
    // secondary sessions infos
    case 'init':
    {
    lSecondaryDataSessionInterfaceInfo = pMessage.dataSession;
    lDataSessionBuildId = pMessage.buildId;
    const lResult : AuthenticationGetURLResult = lSecondaryDirectorySession.openSecondaryDirectorySession(pMessage.directorySession);
    if(lResult !== AuthenticationGetURLResult.AuthenticationPending)
    {
    // and output some message if the data session opening failed
    console.error('directory session opening failed');
    // and tell the primary session to get rid of the secondary session
    sendMessage({ type: 'dataSessionCleanup' });
    }
    break;
    }
    case 'directorySessionTokens':
    {
    // do nothing if the directory session is not connected
    if(!lSecondaryDirectorySession.isAuthenticated())
    {
    return;
    }
    // and update the tokens
    const lResult : boolean = lSecondaryDirectorySession.setTokenValues(pMessage.httpBearer, pMessage.authenticationBearer, pMessage.extendedAuthenticationBearer);
    if(!lResult)
    {
    // and output some message if the token update failed
    console.error('set token values failed');
    // and tell the primary session to get rid of the secondary session
    sendMessage({ type: 'dataSessionCleanup' });
    }
    break;
    }
    case 'dataSessionTokens':
    {
    // do nothing if the data session is not connected nor created
    if(lSecondaryDataSession === undefined || !lSecondaryDataSession.isConnected())
    {
    return;
    }
    // and update the tokens
    const lResult : boolean = lSecondaryDataSession.setTokenValues(pMessage.dataSessionBearer, pMessage.extendedDataSessionBearer);
    if(!lResult)
    {
    // and output some message if the token update failed
    console.error('set token values failed');
    // and tell the primary session to get rid of the secondary session
    sendMessage({ type: 'dataSessionCleanup' });
    }
    break;
    }
    default:
    // this should not happen, we have no other message types that we may receive
    console.error('Unexpected message type');
    break;
    }
    };

    // register callbacks
    lSecondaryDirectorySession.addEventListener(DirectorySessionInterfaceSignal.LoginSuccess, onLoginSuccess);
    registerMessageHandler(onMessage);
    };

    // in the primary part
    primaryCode();

    // in the secondary part
    secondaryCode();

    Parameters

    • pDataSessionBearer: string
      in
      The updated DataSessionInterface bearer (queried with getDataSessionBearer).
    • pExtendedDataSessionBearer: string
      in
      The optional updated DataSessionInterface extended bearer (queried with getExtendedDataSessionBearer).

    Returns boolean

    true if the call succeeded.

  • Gets a deep copy of the internal data of the DataSessionInterface.

    Please refer to JSON.stringify.

    Parameters

    • Optional pKey: any
      in
      Unused.

    Returns Object

    The internal DataSessionInterface data.

  • Un-registers a secondary DataSessionInterface when the created secondary DataSessionInterface is no longer in use.

    The exact same SecondaryDataSessionInterfaceInfo that was created with requestNewSecondaryDataSession should be used.

    /** 
    * Sample to illustrate the use of the primary/secondary session mechanism of DirectorySessionInterface and DataSessionInterface.
    */
    import {
    InfiniteCacheFactory, DirectorySessionFactory,
    InfiniteCacheInterface, DirectorySessionInterface,
    DataSessionInterface,
    DataSessionInterfaceSignal, DirectorySessionInterfaceSignal,
    SecondaryDirectorySessionInterfaceInfo,
    SecondaryDataSessionInterfaceInfo,
    AuthenticationGetURLResult,
    } from 'generated_files/documentation/appinfiniteapi';

    // this sample holds the code to be use in the primary tab (primaryCode)
    // and in the secondary tab (secondaryCode)

    // a callback to receive messages
    type tMessageHandler = (pMessage: any) => void;

    // we suppose that there exists a message system
    let sendMessage : (pMessage: any) => void;

    // we suppose that we can register a handler to receive messages
    let registerMessageHandler : (pMessageHandler: tMessageHandler) => void;

    // the primary code
    const primaryCode = () : void =>
    {
    // created previously
    // this is the directory session that will server as primary session
    // this DirectorySessionInterface should already be logged in
    let lOriginalDirectorySession : DirectorySessionInterface;

    // created previously
    // this is the data session that will server as primary session
    // this DataSessionInterface should already be primary session
    let lOriginalDataSession : DataSessionInterface;

    // create a secondary session info to init the future secondary DirectorySessionInterface
    const lSecondaryDirectorySessionInfo : SecondaryDirectorySessionInterfaceInfo | undefined = lOriginalDirectorySession.requestNewSecondaryDirectorySession();
    if(lSecondaryDirectorySessionInfo === undefined)
    {
    // output some fancy error message
    console.error('secondary directory session info creation failed');
    return;
    }

    // create a secondary session info to init the future secondary DataSessionInterface
    // warning : this call will hold resources in the primary DataSessionInterface
    // when the secondary data session is no longer useful
    // release resources with unregisterSecondaryDataSession
    // warning: there is a finite number of secondary data sessions that may be created
    let lSecondaryDataSessionInfo : SecondaryDataSessionInterfaceInfo | undefined = lOriginalDataSession.requestNewSecondaryDataSession();
    if(lSecondaryDataSessionInfo === undefined)
    {
    // output some fancy error message
    console.error('secondary data session info creation failed');
    return;
    }

    // called when the DirectorySessionInterface updates its tokens
    const lDirectorySessionTokenUpdate = () : void => {
    const lHttpBearer : string = lOriginalDirectorySession.getHttpBearer();
    // only update tokens when the directory session is connected
    if(lHttpBearer.length > 0)
    {
    // send the new directory session tokens to the secondary
    sendMessage({
    type: 'directorySessionTokens',
    httpBearer: lHttpBearer,
    authenticationBearer: lOriginalDirectorySession.getAuthenticationBearer(),
    extendedAuthenticationBearer: lOriginalDirectorySession.getExtendedAuthenticationBearer(),
    });
    }
    };

    // called when the DataSessionInterface updates its tokens
    const lDataSessionTokenUpdate = () : void => {
    const lDataSessionBearer : string = lOriginalDataSession.getDataSessionBearer();
    // only update tokens when the data session is connected
    if(lDataSessionBearer.length > 0)
    {
    // send the new data session tokens to the secondary session
    sendMessage({
    type: 'dataSessionTokens',
    dataSessionBearer: lDataSessionBearer,
    extendedDataSessionBearer: lOriginalDataSession.getExtendedDataSessionBearer(),
    });
    }
    };

    // message callback, receive messages from the secondary session
    const onMessage : tMessageHandler = (pMessage : any) : void =>
    {
    switch(pMessage.type)
    {
    // cleanup the secondary session resources
    case 'dataSessionCleanup':
    if(lSecondaryDataSessionInfo !== undefined)
    {
    lOriginalDataSession.unregisterSecondaryDataSession(lSecondaryDataSessionInfo);
    // cleanup only once
    lSecondaryDataSessionInfo = undefined;
    }
    break;
    default:
    // this should not happen, we have no other message types that we may receive
    console.error('Unexpected message type');
    break;
    }
    };

    // and register the token update functions on token update
    lOriginalDirectorySession.addEventListener(DirectorySessionInterfaceSignal.TokenUpdated, lDirectorySessionTokenUpdate);
    lOriginalDataSession.addEventListener(DataSessionInterfaceSignal.TokenUpdated, lDataSessionTokenUpdate);
    // register callbacks
    registerMessageHandler(onMessage);

    // we are ready, send the infos to load a new secondary directory and data session
    sendMessage({
    type: 'init',
    directorySession: lSecondaryDirectorySessionInfo,
    dataSession: lSecondaryDataSessionInfo,
    // build id is required to create a data session on the correct build
    buildId: lOriginalDataSession.getBuildId()
    });
    };

    // the secondary session code
    const secondaryCode = () : void =>
    {
    // create a directory session
    const sDirectoryUrl : string = 'https://my_directory:443/directory';
    // before connection, this is a "normal" one
    const lSecondaryDirectorySession : DirectorySessionInterface = DirectorySessionFactory.CreateDirectorySession(sDirectoryUrl);
    // Create a cache to avoid requesting heavy data from the server if data has been retrieved already
    const lCache: InfiniteCacheInterface = InfiniteCacheFactory.CreateInfiniteCache();
    // the new data session
    // we cannot create it right now, we must wait for secondary session info and directory session login
    let lSecondaryDataSession : DataSessionInterface;
    // hold the open secondary session info for future call
    let lSecondaryDataSessionInterfaceInfo : SecondaryDataSessionInterfaceInfo;
    // the build id we will be connected to
    let lDataSessionBuildId : string = '';

    // Success callback on DirectorySessionInterface login
    const onLoginSuccess = () : void => {
    // weird, we should have a build id at this time
    if(lDataSessionBuildId.length === 0)
    {
    // and output some message if the data session creation failed
    console.error('data session creation failed, empty build id');
    // and tell the primary session to get rid of the secondary session
    sendMessage({ type: 'dataSessionCleanup' });
    return;
    }
    // actually create the DataSessionInterface
    lSecondaryDataSession = lSecondaryDirectorySession.createDataSession(lDataSessionBuildId, lCache);
    if(lSecondaryDataSession === undefined)
    {
    // and output some message if the data session creation failed
    console.error('data session creation failed');
    // and tell the primary session to get rid of the secondary session
    sendMessage({ type: 'dataSessionCleanup' });
    return;
    }
    // open it in secondary session mode
    if(!lSecondaryDataSession.openSecondaryDataSession(lSecondaryDataSessionInterfaceInfo))
    {
    // and output some message if the data session opening failed
    console.error('secondary data session opening failed');
    // get rid of data
    lSecondaryDataSession.dispose();
    lSecondaryDataSession = undefined;
    // and tell the primary session to get rid of the secondary session
    sendMessage({ type: 'dataSessionCleanup' });
    }
    // and then we must wait for the DataSessionInterface to be connected
    };

    // message callback, receive secondary sessions info and tokens
    const onMessage : tMessageHandler = (pMessage : any) : void =>
    {
    switch(pMessage.type)
    {
    // secondary sessions infos
    case 'init':
    {
    lSecondaryDataSessionInterfaceInfo = pMessage.dataSession;
    lDataSessionBuildId = pMessage.buildId;
    const lResult : AuthenticationGetURLResult = lSecondaryDirectorySession.openSecondaryDirectorySession(pMessage.directorySession);
    if(lResult !== AuthenticationGetURLResult.AuthenticationPending)
    {
    // and output some message if the data session opening failed
    console.error('directory session opening failed');
    // and tell the primary session to get rid of the secondary session
    sendMessage({ type: 'dataSessionCleanup' });
    }
    break;
    }
    case 'directorySessionTokens':
    {
    // do nothing if the directory session is not connected
    if(!lSecondaryDirectorySession.isAuthenticated())
    {
    return;
    }
    // and update the tokens
    const lResult : boolean = lSecondaryDirectorySession.setTokenValues(pMessage.httpBearer, pMessage.authenticationBearer, pMessage.extendedAuthenticationBearer);
    if(!lResult)
    {
    // and output some message if the token update failed
    console.error('set token values failed');
    // and tell the primary session to get rid of the secondary session
    sendMessage({ type: 'dataSessionCleanup' });
    }
    break;
    }
    case 'dataSessionTokens':
    {
    // do nothing if the data session is not connected nor created
    if(lSecondaryDataSession === undefined || !lSecondaryDataSession.isConnected())
    {
    return;
    }
    // and update the tokens
    const lResult : boolean = lSecondaryDataSession.setTokenValues(pMessage.dataSessionBearer, pMessage.extendedDataSessionBearer);
    if(!lResult)
    {
    // and output some message if the token update failed
    console.error('set token values failed');
    // and tell the primary session to get rid of the secondary session
    sendMessage({ type: 'dataSessionCleanup' });
    }
    break;
    }
    default:
    // this should not happen, we have no other message types that we may receive
    console.error('Unexpected message type');
    break;
    }
    };

    // register callbacks
    lSecondaryDirectorySession.addEventListener(DirectorySessionInterfaceSignal.LoginSuccess, onLoginSuccess);
    registerMessageHandler(onMessage);
    };

    // in the primary part
    primaryCode();

    // in the secondary part
    secondaryCode();

    Parameters

    Returns boolean

    true if the call succeeded.

  • Triggers the calculation of all modified WorkingSetInterface, FilterItemInterfaces.

    All the modified items are updated on the server according to their inter-dependencies.

    The relevant interfaces will asynchronously trigger a "ready" signal when their calculation is over.

    Returns void