Interface DirectorySessionInterface

The DirectorySessionInterface is in charge of the authentication of a user to the 3djuump Infinite architecture, and the initiation of a connection to a 3djuump Infinite proxy.

The DirectorySessionInterface is the formalization of the session to a 3djuump Infinite directory.

The 3djuump Infinite architecture does not feature an internal authentication procedure, but delegates the authentication to an external authentication server by the use of an openid connect protocol.

There is at the moment only 2 ways to authenticate to the 3djuump Infinite directory, by the use of a popup window (getPopupBasedAuthenticationUrl, DirectorySessionFactory.DecodeAuthenticationHash) or a same page authentication (getSamePageAuthenticationUrl, setTokenFromHash).

  1. With the popup based authentication. The user will see a new tab opened to the authentication server, asking for a user/password, and at the end a redirection to a custom authentication page (e.g. authenticate.html) with a script that calls DirectorySessionFactory.DecodeAuthenticationHash (see the main page for more information). Depending on your openid configuration, this procedure may be silent for the end-user, with the use of SSO and automatic login. The user may then need to close the authentication tab (or perhaps closed automatically). It is your responsibility to open a new tab (see the code below).
/** 
* Sample to illustrate the popup based authentication mechanism.
*/
import {
InfiniteFactory, InfiniteCacheFactory, DirectorySessionFactory,
InfiniteEngineInterface, InfiniteCacheInterface, DirectorySessionInterface,
InfiniteEvent, ConnectionData,
DataSessionInterfaceSignal, DirectorySessionInterfaceSignal,
} from 'generated_files/documentation/appinfiniteapi';

// authentication url as defined in the directory
// authenticate.html must include your authentication script
const sAuthenticationUrl : string = 'https://your_server/your_application/authenticate.html';
const sDirectoryUrl : string = 'https://my_directory:443/directory';

// Create a 3D engine to handle the rendering of the DMU. The engine is optional if you
// just want to search data in the DMU, but required to display 3D data.
// you need to provide a div inside your html file, or create one div programmatically
const lInfiniteEngine: InfiniteEngineInterface = InfiniteFactory.CreateInfiniteEngine();
// bind the engine to the given div that will be used for rendering
lInfiniteEngine.setView(document.getElementById('rendering'));
// Create a cache to avoid requesting heavy data from the server if data has been retrieved already
const lCache: InfiniteCacheInterface = InfiniteCacheFactory.CreateInfiniteCache();

// what to do to authenticate (authenticate function may be bound to a div `click` or called straight away)
let authenticate : () => void = undefined;

// Success callback on login
let onLoginSuccess : (pEvent: InfiniteEvent, _pCallbackData: Object | undefined) => void = undefined;

// Success callback when DataSession is ready
let onDMULoaded : (_pEvent: InfiniteEvent, _pCallbackData: Object | undefined) => void = undefined;

// *****************************************************************************
// ******************************* Authentication ******************************
// *****************************************************************************
// what to do to authenticate (authenticate function may be bound to a div `click` or called straight away)
authenticate = () : void =>
{
// connect to directory with address sDirectoryAddress, in the folder "/directory" through https. The default port is unchanged (443)
const lDirectorySession: DirectorySessionInterface = DirectorySessionFactory.CreateDirectorySession(sDirectoryUrl);

// do something when we are connected !!!! => onLoginSuccess
lDirectorySession.addEventListener(DirectorySessionInterfaceSignal.LoginSuccess, onLoginSuccess);

// retrieve the url to contact to begin authentication with popup
// that also starts the authentication procedure
const sURL = lDirectorySession.getPopupBasedAuthenticationUrl(sAuthenticationUrl);
if (typeof sURL === 'string') {
if (sURL !== '' && sURL.includes('authenticate'))
{
// popup based authentication
window.open(sURL);
}
}
};

// Success callback on login
onLoginSuccess = (pEvent: InfiniteEvent, _pCallbackData: Object | undefined) : void =>
{
// Get the Connection Data to get the build lists
const lConnectionData: ConnectionData = <ConnectionData>pEvent.attachments;

// Get the list of projects => do something as you like
const lProjectList = lConnectionData.projects;
for (const lProjectId in lProjectList)
{
// iterate but get the first project
const lBuildList = lProjectList[lProjectId].builds;
for (const lBuild in lBuildList)
{
// iterate but get the first build
// create a data session that uses the cache with the first item
const lDataSession = (<DirectorySessionInterface>(pEvent.emitter)).createDataSession(lBuild, lCache);
if (lDataSession)
{
// bind the given data session to the Infinite engine
lDataSession.bindInfiniteEngine(lInfiniteEngine);
// be ready to do something when build is ready (i.e. all init data has been parsed and server is ready)
lDataSession.addEventListener(DataSessionInterfaceSignal.DMULoadingSuccess, onDMULoaded);
// and go !!! => open the data session
lDataSession.openDataSession();
}
return;
}
}
};

// Success callback when DataSession is ready
onDMULoaded = (_pEvent: InfiniteEvent, _pCallbackData: Object | undefined) : void =>
{
// do something !!!
// create filters
// change visibility
// etc ....
};

authenticate();

2. With the same page authentication. The user will see multiple redirects (the number depending on your openid connect server and its configuration) from the current tab and will be finally redirected to the start page of your application. The last redirect will be done with a hash parameter that contains authentication information. The developer may need to store url parameters in the browser storage (or use the DirectoryAuthenticationOption.applicationData) to be redirected to the final url (see the main page for more information). The authentication procedure is initiated with getSamePageAuthenticationUrl which should return the redirection url to visit, and then setTokenFromHash on the last redirect. The setTokenFromHash will normally send DirectorySessionInterfaceSignal.LoginSuccess asynchronously.
/** 
* Sample to illustrate the same page authentication mechanism.
*/
import {
InfiniteFactory, InfiniteCacheFactory, DirectorySessionFactory,
InfiniteEngineInterface, InfiniteCacheInterface, DirectorySessionInterface,
InfiniteEvent, ConnectionData,
DataSessionInterfaceSignal, DirectorySessionInterfaceSignal,
} from 'generated_files/documentation/appinfiniteapi';

// the current page (without url parameters) should be registered as authentication url in the directory
const sDirectoryUrl : string = 'https://my_directory:443/directory';

let lInfiniteEngine: InfiniteEngineInterface | undefined = undefined;
let lCache: InfiniteCacheInterface | undefined = undefined;
let lDirectorySession: DirectorySessionInterface | undefined = undefined;

// what to do to authenticate (authenticate function may be bound to a div `click` or called straight away)
let authenticate : () => void = undefined;

// Checks if the url has an hash in order to authenticate
let checkHash : () => void = undefined;

// Success callback on login
let onLoginSuccess : (pEvent: InfiniteEvent, _pCallbackData: Object | undefined) => void;

// Success callback when DataSession is ready
let onDMULoaded : (_pEvent: InfiniteEvent, _pCallbackData: Object | undefined) => void;

// *****************************************************************************
// ******************************* Authentication ******************************
// *****************************************************************************
// what to do to authenticate (authenticate function may be bound to a div `click` or called straight away)
authenticate = () : void =>
{
// if we have a hash, do not request a new authentication
if (window.location.hash.length > 0)
{
// perhaps some GUI code there
return;
}
// connect to directory with address sDirectoryAddress, in the folder "/directory" through https. The default port is unchanged (443)
lDirectorySession = DirectorySessionFactory.CreateDirectorySession(sDirectoryUrl);

// redirect url is the current url without query parameters
// the directory needs a full url (with query parameters if needed), so we recommend to
// register the url without parameters, use this url as authentication, store the url parameters if present
// and then redirect to the "final url" (see checkHash)
const sRedirectUrl : string = window.location.origin + window.location.pathname;
if (window.location.href.includes('?'))
{
// store the url with query parameters in session storage
// we will finally redirect to this url
window.sessionStorage.setItem('redirecturl', window.location.href.split('#')[0]);
}
const sURL = lDirectorySession.getSamePageAuthenticationUrl(sRedirectUrl);
if (typeof sURL === 'string')
{
// navigate to the given url for authentication
window.location.href = sURL;
}
else
{
console.log('Error not expected !!! ' + sURL);
window.sessionStorage.removeItem('redirecturl');
}
};

// Checks if the url has an hash in order to authenticate
checkHash = () : void =>
{
const lHash : string = window.location.hash;
if (lHash.length === 0)
{
// do not bother if no hash
return;
}
// we may here put some GUI code

// here we can check if the url has query parameters
const lSessionItem : string | null = window.sessionStorage.getItem('redirecturl');
if (lSessionItem)
{
// we have a redirect url
// remove it from storage in order to avoid infinite redirects
window.sessionStorage.removeItem('redirecturl');
// navigate to this url with hash
window.location.replace(lSessionItem + lHash);
}
else
{
// remove hash with some fancy methods
if (window.history.replaceState)
{
const uri : string = window.location.toString();
const cleanUri : string = uri.substring(0, uri.indexOf('#'));
window.history.replaceState({}, document.title, cleanUri);
}
else
{
window.location.hash = '';
}

lDirectorySession = DirectorySessionFactory.CreateDirectorySession(sDirectoryUrl);
// do something when we are connected !!!! => onLoginSuccess
lDirectorySession.addEventListener(DirectorySessionInterfaceSignal.LoginSuccess, onLoginSuccess);
// and end authentication
lDirectorySession.setTokenFromHash(lHash);
}
};

// Success callback on login
onLoginSuccess = (pEvent: InfiniteEvent, _pCallbackData: Object | undefined) : void =>
{
// Create a 3D engine to handle the rendering of the DMU. The engine is optional if you
// just want to search data in the DMU, but required to display 3D data.
// you need to provide a div inside your html file, or create one div programmatically
lInfiniteEngine = InfiniteFactory.CreateInfiniteEngine();
// bind the engine to the given div that will be used for rendering
lInfiniteEngine.setView(document.getElementById('rendering'));
// Create a cache to avoid requesting heavy data from the server if data has been retrieved already
lCache = InfiniteCacheFactory.CreateInfiniteCache();
// Get the Connection Data to get the build lists
const lConnectionData: ConnectionData = <ConnectionData>pEvent.attachments;

// Get the list of projects => do something as you like
const lProjectList = lConnectionData.projects;
for (const lProjectId in lProjectList)
{
// iterate but get the first project
const lBuildList = lProjectList[lProjectId].builds;
for (const lBuild in lBuildList)
{
// iterate but get the first build
// create a data session that uses the cache with the first item
const lDataSession = (<DirectorySessionInterface>(pEvent.emitter)).createDataSession(lBuild, lCache);
if (lDataSession)
{
lDataSession.bindInfiniteEngine(lInfiniteEngine);
// be ready to do something when build is ready (i.e. all init data has been parsed and server is ready)
lDataSession.addEventListener(DataSessionInterfaceSignal.DMULoadingSuccess, onDMULoaded);
// and go !!! => open the data session
lDataSession.openDataSession();
}
return;
}
}
};

// Success callback when DataSession is ready
onDMULoaded = (_pEvent: InfiniteEvent, _pCallbackData: Object | undefined) : void =>
{
// do something !!!
// create filters
// change visibility
// etc ....
};

// we may launch an authentication procedure (or from a button)
authenticate();

// check hash if we should validate the authentication
checkHash();

Upon a successful connection, user access rights are retrieved asynchronously with the connection to the DirectorySessionInterfaceSignal.LoginSuccess signal. User access rights are formalized with the ConnectionData object, that contains the list of tags, teams attached to this user, and also the available builds/projects for this user. You can force the refreshing of this information with a call to refreshAccessRightsInfo.

The DirectorySessionInterface is the factory to a DataSessionInterface that allows to choose a specific proxy to connect to, and begin downloading / initializing data.

The same DirectorySessionInterface may be shared upon multiple tabs. In order to do so, one DirectorySessionInterface plays the role of the 'primary session' while others play the role of secondary ones. The secondary session must be opened with openSecondaryDirectorySession, and regularly updated with setTokenValues when the primary DirectorySessionInterface triggers a DirectorySessionInterfaceSignal.TokenUpdated (and bearers are retrieved with getAuthenticationBearer, getExtendedAuthenticationBearer and getHttpBearer).

/** 
* 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 see DataSessionInterface for more explanations about sessions.
Sessions

interface DirectorySessionInterface {
    addEventListener(pType, pListener, pObject): string;
    addEventListener(pType, pListener): string;
    areSignalsBlocked(): boolean;
    asyncCloseDirectorySession(pForceAuthentication): Promise<void>;
    asyncOpenSecondaryDirectorySession(pSecondarySessionInfo): Promise<AsyncDirectorySessionWaitForLoadedResult>;
    asyncRefreshAccessRightsInfo(): Promise<AsyncDirectorySessionWaitForRefreshAccessRightsResult>;
    asyncWaitForPopupAuthentication(): Promise<AsyncDirectorySessionWaitForLoadedResult>;
    blockSignals(pBlock): void;
    closeDirectorySession(pForceAuthentication): void;
    createDataSession(pBuildId, pCache): DataSessionInterface;
    dispose(): void;
    getApiUrl(): string;
    getApplicationData(): string;
    getApplicationGrantedScopes(pScopes): boolean;
    getAuthenticationBearer(): string;
    getCurrentTokenHash(): string;
    getDirectoryApplicationId(): string;
    getDirectorySessionId(): string;
    getExtendedAuthenticationBearer(): string;
    getHttpBearer(): string;
    getInfiniteObjectType(): InfiniteObjectType;
    getPopupBasedAuthenticationUrl(pRedirectURI, pOpenOptions?): string | AuthenticationGetURLResult;
    getSamePageAuthenticationUrl(pRedirectURI, pOpenOptions?): string | AuthenticationGetURLResult;
    getUserInfo(): UserData;
    hasEventListener(pType, pListener): boolean;
    hasEventListenerById(pId): boolean;
    isAuthenticated(): boolean;
    isDisposed(): boolean;
    isPrimaryBehavior(): boolean;
    openSecondaryDirectorySession(pSecondarySessionInfo): AuthenticationGetURLResult;
    refreshAccessRightsInfo(): boolean;
    removeAllEventListeners(): boolean;
    removeEventListener(pType, pListener, pObject): boolean;
    removeEventListener(pType, pListener): boolean;
    removeEventListenerById(pId): boolean;
    requestNewSecondaryDirectorySession(): SecondaryDirectorySessionInterfaceInfo;
    setTokenFromHash(pHash): AuthenticationGetURLResult;
    setTokenValues(pHttpBearer, pAuthenticationBearer, pExtendedAuthenticationBearer): boolean;
}

Hierarchy (view full)

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.

  • Asynchronously opens a DirectorySessionInterface in secondary session mode.

    Once a DirectorySessionInterface has been fully loaded, a secondary DirectorySessionInterface may be open with asyncOpenSecondaryDirectorySession with the result of requestNewSecondaryDirectorySession called on the primary DirectorySessionInterface.

    /** 
    * 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();

    Returns Promise<AsyncDirectorySessionWaitForLoadedResult>

    A promise.

  • 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

  • Creates a data session concerning the given build id, with the given cache.

    open data session sequence
    The proxy selection is automatic and inferred by current CPU workloads.

    Parameters

    • pBuildId: string
      in
      The build id to connect to.
    • pCache: InfiniteCacheInterface
      in
      The optional cache to use to speed up data retrieving (if relevant), may be undefined.

    Returns DataSessionInterface

    The newly data session or undefined if the DirectorySessionInterface is not authenticated to the directory.

  • Gets the URL to the 3djuump Infinite directory API.

    It is https://pDirectoryHost:pDirectoryPort/pDirectoryPath/ which was set by the factory DirectorySessionFactory.CreateDirectorySession.

    Returns string

    The URL string of the directory API.

  • Gets the scopes that were granted by the infinite backend.

    If the user has any access right thirdpartyscopes:any_value (attached to her, her team or the application) and any_value is requested through DirectoryAuthenticationOption.appClaims, then the user will be granted any_value has scope.

    This feature is useful to then make some request to a third party server with the directory token.

    Parameters

    • pScopes: string[]
      out
      The application scopes granted by the infinite backend.

    Returns boolean

    true if the call succeeded, i.e. pScopes is an Array.

  • Gets the Infinite token of the current directory session authentication.

    Any http request to the directory should have the header x-infinite-bearer : <DirectorySessionInterface.getAuthenticationBearer()>.

    If the directory session is not connected, returns an empty string.

    Returns string

    The Infinite token.

  • Gets the id of the application as registered in the 3djuump Infinite admin page.

    This may be used to call specific api calls to the Infinite backend.

    If the authentication has not been performed, returns an empty strings.

    Returns string

    The directory application id.

  • Gets the id of the directory session.

    This may be used to call specific api calls to the Infinite backend.

    If the authentication has not been performed, returns an empty strings.

    Returns string

    The directory session id.

  • Gets the Bearer of the current http directory session authentication.

    Any http request to the directory should have the header Authorization : Bearer <DirectorySessionInterface.getHttpBearer()>.

    If the directory session is not connected, returns an empty string.

    Returns string

    The Bearer of the http authentication.

  • Opens a new authentication session on the directory with the pop up mechanism, asking the user to authenticate.

    A new tab is not opened by this function, the user will have to call window.open(getPopupBasedAuthenticationUrl()). Depending on your openid connect configuration, this may be a silent procedure for the user. This function makes use of the localStorage of the browser internally.

    This function may return a string if successful, AuthenticationGetURLResult.DoNotReAuthenticate if the DirectorySessionInterface is already connected, AuthenticationGetURLResult.InvalidSession if an internal error occurred (unlikely) and AuthenticationGetURLResult.EmptyCallbackURI if pRedirectURI is an empty string.

    An extended token may be requested with the options, in this case, the access token will contain additional information (subid, teams, etc ...). An application data may also be passed along. Some application claims may also be passed along.

    /** 
    * Sample to illustrate the popup based authentication mechanism.
    */
    import {
    InfiniteFactory, InfiniteCacheFactory, DirectorySessionFactory,
    InfiniteEngineInterface, InfiniteCacheInterface, DirectorySessionInterface,
    InfiniteEvent, ConnectionData,
    DataSessionInterfaceSignal, DirectorySessionInterfaceSignal,
    } from 'generated_files/documentation/appinfiniteapi';

    // authentication url as defined in the directory
    // authenticate.html must include your authentication script
    const sAuthenticationUrl : string = 'https://your_server/your_application/authenticate.html';
    const sDirectoryUrl : string = 'https://my_directory:443/directory';

    // Create a 3D engine to handle the rendering of the DMU. The engine is optional if you
    // just want to search data in the DMU, but required to display 3D data.
    // you need to provide a div inside your html file, or create one div programmatically
    const lInfiniteEngine: InfiniteEngineInterface = InfiniteFactory.CreateInfiniteEngine();
    // bind the engine to the given div that will be used for rendering
    lInfiniteEngine.setView(document.getElementById('rendering'));
    // Create a cache to avoid requesting heavy data from the server if data has been retrieved already
    const lCache: InfiniteCacheInterface = InfiniteCacheFactory.CreateInfiniteCache();

    // what to do to authenticate (authenticate function may be bound to a div `click` or called straight away)
    let authenticate : () => void = undefined;

    // Success callback on login
    let onLoginSuccess : (pEvent: InfiniteEvent, _pCallbackData: Object | undefined) => void = undefined;

    // Success callback when DataSession is ready
    let onDMULoaded : (_pEvent: InfiniteEvent, _pCallbackData: Object | undefined) => void = undefined;

    // *****************************************************************************
    // ******************************* Authentication ******************************
    // *****************************************************************************
    // what to do to authenticate (authenticate function may be bound to a div `click` or called straight away)
    authenticate = () : void =>
    {
    // connect to directory with address sDirectoryAddress, in the folder "/directory" through https. The default port is unchanged (443)
    const lDirectorySession: DirectorySessionInterface = DirectorySessionFactory.CreateDirectorySession(sDirectoryUrl);

    // do something when we are connected !!!! => onLoginSuccess
    lDirectorySession.addEventListener(DirectorySessionInterfaceSignal.LoginSuccess, onLoginSuccess);

    // retrieve the url to contact to begin authentication with popup
    // that also starts the authentication procedure
    const sURL = lDirectorySession.getPopupBasedAuthenticationUrl(sAuthenticationUrl);
    if (typeof sURL === 'string') {
    if (sURL !== '' && sURL.includes('authenticate'))
    {
    // popup based authentication
    window.open(sURL);
    }
    }
    };

    // Success callback on login
    onLoginSuccess = (pEvent: InfiniteEvent, _pCallbackData: Object | undefined) : void =>
    {
    // Get the Connection Data to get the build lists
    const lConnectionData: ConnectionData = <ConnectionData>pEvent.attachments;

    // Get the list of projects => do something as you like
    const lProjectList = lConnectionData.projects;
    for (const lProjectId in lProjectList)
    {
    // iterate but get the first project
    const lBuildList = lProjectList[lProjectId].builds;
    for (const lBuild in lBuildList)
    {
    // iterate but get the first build
    // create a data session that uses the cache with the first item
    const lDataSession = (<DirectorySessionInterface>(pEvent.emitter)).createDataSession(lBuild, lCache);
    if (lDataSession)
    {
    // bind the given data session to the Infinite engine
    lDataSession.bindInfiniteEngine(lInfiniteEngine);
    // be ready to do something when build is ready (i.e. all init data has been parsed and server is ready)
    lDataSession.addEventListener(DataSessionInterfaceSignal.DMULoadingSuccess, onDMULoaded);
    // and go !!! => open the data session
    lDataSession.openDataSession();
    }
    return;
    }
    }
    };

    // Success callback when DataSession is ready
    onDMULoaded = (_pEvent: InfiniteEvent, _pCallbackData: Object | undefined) : void =>
    {
    // do something !!!
    // create filters
    // change visibility
    // etc ....
    };

    authenticate();

    See the main page for more information.

    Parameters

    • pRedirectURI: string
      in
      The redirect url where the authentication server should redirect on the completion of the authentication procedure (successful or not). An empty string will result in an error.
    • Optional pOpenOptions: DirectoryAuthenticationOption
      in
      If defined, you may add extended token request, and also some applicative data.

    Returns string | AuthenticationGetURLResult

    The authentication URL to visit to start the authentication procedure if successful, AuthenticationGetURLResult.DoNotReAuthenticate if the DirectorySessionInterface is already connected, AuthenticationGetURLResult.InvalidSession if an internal error occurred and AuthenticationGetURLResult.EmptyCallbackURI if pRedirectURI is an empty string.

  • Opens a new authentication session on the directory with the same page mechanism, asking the user to authenticate.

    Depending on your openid connect configuration, this may be a silent procedure for the user.

    This function may return a string if successful, AuthenticationGetURLResult.DoNotReAuthenticate if the DirectorySessionInterface is already connected, AuthenticationGetURLResult.InvalidSession if an internal error occurred (unlikely) and AuthenticationGetURLResult.EmptyCallbackURI if pRedirectURI is an empty string.

    An extended token may be requested with the options, in this case, the access token will contain additional information (subid, teams, etc ...). An application data may also be passed along. Some application claims may also be passed along.

    /** 
    * Sample to illustrate the same page authentication mechanism.
    */
    import {
    InfiniteFactory, InfiniteCacheFactory, DirectorySessionFactory,
    InfiniteEngineInterface, InfiniteCacheInterface, DirectorySessionInterface,
    InfiniteEvent, ConnectionData,
    DataSessionInterfaceSignal, DirectorySessionInterfaceSignal,
    } from 'generated_files/documentation/appinfiniteapi';

    // the current page (without url parameters) should be registered as authentication url in the directory
    const sDirectoryUrl : string = 'https://my_directory:443/directory';

    let lInfiniteEngine: InfiniteEngineInterface | undefined = undefined;
    let lCache: InfiniteCacheInterface | undefined = undefined;
    let lDirectorySession: DirectorySessionInterface | undefined = undefined;

    // what to do to authenticate (authenticate function may be bound to a div `click` or called straight away)
    let authenticate : () => void = undefined;

    // Checks if the url has an hash in order to authenticate
    let checkHash : () => void = undefined;

    // Success callback on login
    let onLoginSuccess : (pEvent: InfiniteEvent, _pCallbackData: Object | undefined) => void;

    // Success callback when DataSession is ready
    let onDMULoaded : (_pEvent: InfiniteEvent, _pCallbackData: Object | undefined) => void;

    // *****************************************************************************
    // ******************************* Authentication ******************************
    // *****************************************************************************
    // what to do to authenticate (authenticate function may be bound to a div `click` or called straight away)
    authenticate = () : void =>
    {
    // if we have a hash, do not request a new authentication
    if (window.location.hash.length > 0)
    {
    // perhaps some GUI code there
    return;
    }
    // connect to directory with address sDirectoryAddress, in the folder "/directory" through https. The default port is unchanged (443)
    lDirectorySession = DirectorySessionFactory.CreateDirectorySession(sDirectoryUrl);

    // redirect url is the current url without query parameters
    // the directory needs a full url (with query parameters if needed), so we recommend to
    // register the url without parameters, use this url as authentication, store the url parameters if present
    // and then redirect to the "final url" (see checkHash)
    const sRedirectUrl : string = window.location.origin + window.location.pathname;
    if (window.location.href.includes('?'))
    {
    // store the url with query parameters in session storage
    // we will finally redirect to this url
    window.sessionStorage.setItem('redirecturl', window.location.href.split('#')[0]);
    }
    const sURL = lDirectorySession.getSamePageAuthenticationUrl(sRedirectUrl);
    if (typeof sURL === 'string')
    {
    // navigate to the given url for authentication
    window.location.href = sURL;
    }
    else
    {
    console.log('Error not expected !!! ' + sURL);
    window.sessionStorage.removeItem('redirecturl');
    }
    };

    // Checks if the url has an hash in order to authenticate
    checkHash = () : void =>
    {
    const lHash : string = window.location.hash;
    if (lHash.length === 0)
    {
    // do not bother if no hash
    return;
    }
    // we may here put some GUI code

    // here we can check if the url has query parameters
    const lSessionItem : string | null = window.sessionStorage.getItem('redirecturl');
    if (lSessionItem)
    {
    // we have a redirect url
    // remove it from storage in order to avoid infinite redirects
    window.sessionStorage.removeItem('redirecturl');
    // navigate to this url with hash
    window.location.replace(lSessionItem + lHash);
    }
    else
    {
    // remove hash with some fancy methods
    if (window.history.replaceState)
    {
    const uri : string = window.location.toString();
    const cleanUri : string = uri.substring(0, uri.indexOf('#'));
    window.history.replaceState({}, document.title, cleanUri);
    }
    else
    {
    window.location.hash = '';
    }

    lDirectorySession = DirectorySessionFactory.CreateDirectorySession(sDirectoryUrl);
    // do something when we are connected !!!! => onLoginSuccess
    lDirectorySession.addEventListener(DirectorySessionInterfaceSignal.LoginSuccess, onLoginSuccess);
    // and end authentication
    lDirectorySession.setTokenFromHash(lHash);
    }
    };

    // Success callback on login
    onLoginSuccess = (pEvent: InfiniteEvent, _pCallbackData: Object | undefined) : void =>
    {
    // Create a 3D engine to handle the rendering of the DMU. The engine is optional if you
    // just want to search data in the DMU, but required to display 3D data.
    // you need to provide a div inside your html file, or create one div programmatically
    lInfiniteEngine = InfiniteFactory.CreateInfiniteEngine();
    // bind the engine to the given div that will be used for rendering
    lInfiniteEngine.setView(document.getElementById('rendering'));
    // Create a cache to avoid requesting heavy data from the server if data has been retrieved already
    lCache = InfiniteCacheFactory.CreateInfiniteCache();
    // Get the Connection Data to get the build lists
    const lConnectionData: ConnectionData = <ConnectionData>pEvent.attachments;

    // Get the list of projects => do something as you like
    const lProjectList = lConnectionData.projects;
    for (const lProjectId in lProjectList)
    {
    // iterate but get the first project
    const lBuildList = lProjectList[lProjectId].builds;
    for (const lBuild in lBuildList)
    {
    // iterate but get the first build
    // create a data session that uses the cache with the first item
    const lDataSession = (<DirectorySessionInterface>(pEvent.emitter)).createDataSession(lBuild, lCache);
    if (lDataSession)
    {
    lDataSession.bindInfiniteEngine(lInfiniteEngine);
    // be ready to do something when build is ready (i.e. all init data has been parsed and server is ready)
    lDataSession.addEventListener(DataSessionInterfaceSignal.DMULoadingSuccess, onDMULoaded);
    // and go !!! => open the data session
    lDataSession.openDataSession();
    }
    return;
    }
    }
    };

    // Success callback when DataSession is ready
    onDMULoaded = (_pEvent: InfiniteEvent, _pCallbackData: Object | undefined) : void =>
    {
    // do something !!!
    // create filters
    // change visibility
    // etc ....
    };

    // we may launch an authentication procedure (or from a button)
    authenticate();

    // check hash if we should validate the authentication
    checkHash();

    See the main page for more information.

    Parameters

    • pRedirectURI: string
      in
      The redirect url where the authentication server should redirect on the completion of the authentication procedure (successful or not). An empty string will result in an error.
    • Optional pOpenOptions: DirectoryAuthenticationOption
      in
      If defined, you may add extended token request, and also some applicative data.

    Returns string | AuthenticationGetURLResult

    The authentication URL to visit to start the authentication procedure if successful, AuthenticationGetURLResult.DoNotReAuthenticate if the DirectorySessionInterface is already connected, AuthenticationGetURLResult.InvalidSession if an internal error occurred and AuthenticationGetURLResult.EmptyCallbackURI if pRedirectURI is an empty string.

  • Gets a copy of the user information (name, initials and picture URL).

    If the authentication has not been performed, all fields are set to empty strings.

    Returns UserData

    The UserData containing the name (string) the initials (string) and the picture url (string) of the logged-in user.

  • 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 user is authenticated.

    Returns boolean

    true if the user is authenticated.

  • Tells if the DirectorySessionInterface is configured as "primary" session behavior.

    The DirectorySessionInterface is by default configured as "primary" session.

    Once open in secondary session mode with openSecondaryDirectorySession, the DirectorySessionInterface will remain all the time in secondary session mode.

    The primary session behavior consists in updating the bearers (getAuthenticationBearer, getExtendedAuthenticationBearer and getHttpBearer) regularly while a secondary DirectorySessionInterface should receive the new bearers with setTokenValues. This primary/secondary session mechanism allows to use multiple directory sessions objects that share the same directory session on the server. This may be useful to share the same directory session upon multiple tabs of the browser.

    Returns boolean

    true if the DirectorySessionInterface is configured as primary session behavior.

  • Opens a DirectorySessionInterface in secondary session mode.

    Once a DirectorySessionInterface has been fully loaded, a secondary DirectorySessionInterface may be open with openSecondaryDirectorySession with the result of requestNewSecondaryDirectorySession called on the primary DirectorySessionInterface.

    /** 
    * 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();

    Returns AuthenticationGetURLResult

    The result of the opening request.

  • 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 SecondaryDirectorySessionInterfaceInfo in order to create a new secondary DirectorySessionInterface.

    This opaque object may be streamed to another tab (for example) and then used with openSecondaryDirectorySession.

    /** 
    * 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 DirectorySessionInterface across multiple tabs.

    Returns SecondaryDirectorySessionInterfaceInfo

    A new SecondaryDirectorySessionInterfaceInfo if the DirectorySessionInterface is in primary session mode.

  • Sets the content of the bearers.

    This function should only be called when the given DirectorySessionInterface is configured as a secondary session (i.e. openSecondaryDirectorySession has been called). The application may listen for the DirectorySessionInterfaceSignal.TokenUpdated signal on the primary DirectorySessionInterface, then call getAuthenticationBearer, getExtendedAuthenticationBearer and getHttpBearer on the primary session, and finally call setTokenValues on the secondary session.

    Parameters

    • pHttpBearer: string
      in
      The new HTTP bearer.
    • pAuthenticationBearer: string
      in
      The new authentication bearer.
    • pExtendedAuthenticationBearer: string
      in
      The new extended authentication bearer.

    Returns boolean

    true if the call succeeded.