Dodeca HFM Connector

Intro

The Dodeca HFM Connector provides connectivity between the Dodeca client and an Oracle HFM (11.1.2.4+) server. Historically, the Dodeca client makes requests to Essbase servers by communicating using the Dodeca Essbase connector (servlet), which acts as a web service connector between the client and Essbase servers. Similarly, the Dodeca HFM Connector serves much the same role, but between the Dodeca client and an HFM server.

The Dodeca HFM Connector is designed to be API-compatible with the Dodeca Essbase connector. As such, when Dodeca is communicating with HFM via the Dodeca HFM Connector, Dodeca "thinks" it is just communicating with a normal Essbase servlet. Therefore, HFM is utilized in Dodeca as if it were just another Essbase connection.

Not all web service endpoints that exist in the Dodeca Essbase connector are implemented in the HFM connector. An essential (and growing) subset of operations are implemented. For example, the HFM connector implements enough operations to facilitate basic grid retrieval and metadata selectors. Many Dodeca features inherently work automatically because they are part of Dodeca rather than related to Essbase/HFM connector functionality.

Requirements

The Dodeca HFM Connector requires a server with Java 1.8. You can install the connector on an existing Oracle server (such as your middle-tier server with APS, Shared Services, and other components), but you must also install Java 1.8. It is not uncommon for a server to have multiple versions of Java on a single system, but do note that the version of WebLogic used to deploy the EPM product suite requires Java 1.6, so the version of Java used for EPM should not be changed.

Deployment

There are three main steps to deployment:

  1. Extract the Dodeca HFM Connector files to the target server

  2. Copy reg.properties from your EPM server

  3. Copy EPM/HFM Java JAR files from your EPM server to the Dodeca HFM Connector install folder

Extract the Dodeca HFM Connector files to a folder on your server.

The Dodeca HFM Connector zip file just needs to be extracted to a folder on the server you are installing it to. Any folder can be used but it is recommended to a folder in the root of your drive, such as C:\dodeca-hfm-connector. You may wish to put multiple versions of the connector into the folder so you can toggle/upgrade between them as needed, such as having the following folder structure:

C:\
    dodeca-hfm-connector
	    dodeca-hfm-connector-1.1.10
		   ... files ...
		dodeca-hfm-connector-1.2.0
		   ... files ...

Copy reg.properties from EPM server

Find the reg.properties file from your EPM server and copy it to /config in the Dodeca HFM Connector folder. The Dodeca HFM Connector requires this file in order to connect to your Shared Services registry and fetch connection details.

The reg.properties file typically resides in the user_projects subdirectory. If your EPM instance home is /opt/Oracle/Middleware then the full path to reg.properties may be /opt/Oracle/Middleware/user_projects/config/foundation/11.1.2.0/reg.properties. The contents of this file may look similar to the following:

#
#Wed Jun 19 20:12:23 UTC 2019
jdbc.url=jdbc\:weblogic\:sqlserver\://db\:1433;CATALOGOPTIONS\=2;CONNECTIONRETRYDELAY\=1;BULKLOADBATCHSIZE\=1000;DATABASENAME\=EPM_HSS;MAXPOOLEDSTATEMENTS\=0;PROGRAMID\=;ENABLECANCELTIMEOUT\=false;TRUSTSTOREPASSWORD\=;VALIDATESERVERCERTIFICATE\=true;CODEPAGEOVERRIDE\=;DATETIMEINPUTPARAMETERTYPE\=auto;CONNECTIONRETRYCOUNT\=5;ENABLEBULKLOAD\=false;BATCHPERFORMANCEWORKAROUND\=false;INITIALIZATIONSTRING\=;HOSTPROCESS\=0;FAILOVERPRECONNECT\=false;USESERVERSIDEUPDATABLECURSORS\=false;ALWAYSREPORTTRIGGERRESULTS\=false;RESULTSETMETADATAOPTIONS\=0;CLIENTUSER\=;QUERYTIMEOUT\=0;FAILOVERGRANULARITY\=nonAtomic;HOSTNAMEINCERTIFICATE\=;STRINGINPUTPARAMETERTYPE\=nvarchar;SNAPSHOTSERIALIZABLE\=false;APPLICATIONNAME\=;JAVADOUBLETOSTRING\=false;LOADLIBRARYPATH\=;IMPORTSTATEMENTPOOL\=;PROGRAMNAME\=;DATETIMEOUTPUTPARAMETERTYPE\=auto;NETADDRESS\=000000000000;ALTERNATESERVERS\=;DESCRIBEINPUTPARAMETERS\=noDescribe;STRINGOUTPUTPARAMETERTYPE\=nvarchar;WSID\=;BULKLOADOPTIONS\=2;TRUNCATEFRACTIONALSECONDS\=true;ENCRYPTIONMETHOD\=NoEncryption;ACCOUNTINGINFO\=;CONVERTNULL\=1;TRUSTSTORE\=;JDBCBEHAVIOR\=1;FAILOVERMODE\=connect;AUTHENTICATIONMETHOD\=auto;LOGINTIMEOUT\=80;FETCHTWFSASTIME\=false;LONGDATACACHESIZE\=2048;LOADBALANCING\=false;TRANSACTIONMODE\=implicit;DESCRIBEOUTPUTPARAMETERS\=noDescribe;SUPPRESSCONNECTIONWARNINGS\=false;WORKAROUNDS\=0;INSENSITIVERESULTSETBUFFERSIZE\=2048;PACKETSIZE\=-1;CLIENTHOSTNAME\=;DEFAULTSCALE\=4;XMLDESCRIBETYPE\=;FETCHTSWTZASTIMESTAMP\=false;SELECTMETHOD\=direct
password=iTZClekSPGimi2njwWvm2Y/MDxB6qQsFgQDmfjekf8kiASYVAxeUPa30SmGM0b6Q
jdbc.driver=weblogic.jdbc.sqlserver.SQLServerDriver
local.value=lP/ZG4oK/EGbU2i4iNv/NA\=\=
username=sa

Collect HFM Jar Files using Jar Helper tool ("Jarnivore")

The HFM connector ships with a runnable Jar file named Jarnivore that helps analyze and collect the JAR files from an HFM server. The main command on Jarnivore is the copy-deps command. This command takes several parameters, including a target folder, jars to exclude, and the jars to start analyzing.

Jarnivore is specifically compiled to run with Java 1.6 or greater (as opposed to the HFM connector, which presently requires Java 1.8. By only requiring Java 1.6, it is possible to run Jarnivore using any JRE/JDK that is located on your HFM/EPM server.

For example, consider the following command:

java -jar jarnivore.jar copy-deps --target-folder=./hfm-jars-11.1.2.4.208 --exclude=slf4j-api-1.5.8.jar,log4j-1.2.14.jar,slf4j-log4j12-1.5.8.jar %EPM_ORACLE_HOME%\common\jlib\11.1.2.0\epm_j2se.jar %EPM_ORACLE_HOME%\common\jlib\11.1.2.0\epm_hfm_web.jar

For EPM 11.2, Jarnivore has been updated to treat the exclusions list slightly differently. The exclusions now match based on the start of the string, so that Jarnivore is less sensitive to specific versions. The preceding command can and should be written like the following:

java -jar jarnivore.jar copy-deps --target-folder=./hfm-jars-11.1.2.4.208 --exclude=slf4j-api-,log4j-,slf4j-log4j12- %EPM_ORACLE_HOME%\common\jlib\11.1.2.0\epm_j2se.jar %EPM_ORACLE_HOME%\common\jlib\11.1.2.0\epm_hfm_web.jar

This invocation tells Jarnivore to run the "copy dependencies" operation. The HFM jar files to start with are located at the of the command. In this example, the jars to start with are %EPM_ORACLE_HOME%\common\jlib\11.1.2.0\epm_j2se.jar and %EPM_ORACLE_HOME%\common\jlib\11.1.2.0\epm_hfm_web.jar. Note that this particular example relies on the environment variable EPM_ORACLE_HOME to be set, which generally should be. If you want to quickly check if this variable is set you can look for it in the system properties or open up a terminal and type:

echo %EPM_ORACLE_HOME%

If it prints a value then you know the variable is set.

The root jars are epm_j2se.jar and epm_hfm_web.jar. These are both "empty" jars that contain nothing but references to other jars. Those jars in turn contain references to yet more jars. The additional parameters on this command are the target folder, which specifies the single folder to copy all of the found jars into. Lastly, the command specifies certain jars to exclude.

At this time, it is recommended that you exclude the jars shown above (slf4j-api, log4j, slf4j-log4j12) as they are logging jars that will conflict with the Dodeca HFM connector. The Dodeca HFM Connector provides its own jars that are specifically compatible with these jars. Future versions of this connector may simply bring in the default JARs that EPM provides so that the exclusion does not need to be performed.

After the command runs, you will have a directory full of .jar files. If you see any .properties files in the folder, delete them. A future version of Jarnivore will automatically skip them.

Test the HFM connector by running in console mode

You may start the connector by opening a terminal in the /bin folder of the Dodeca HFM connector and then running dodeca-hfm console. This will start the connector in "console" mode, allowing for observing the output. It will possibly take a few minutes for the connector to startup.

Concepts

Many operations in Dodeca implicitly assume that it is working with an Essbase cube and that all members names are unique. However, it is possible for an HFM data source to have duplicate member names For this reason, the Dodeca HFM Connector will 'conceptualize' an HFM outline purely in terms of unique member names. Unique member names are built using HFM member syntax with the dimension short name, a pound sign, and the member name. For example. The "Actual" member from the Scenario dimnension is qualified as "S#Actual". The "January" member from the Period dimension is "P#January".

At present, a grid that is retrieved from HFM must be constucted using fully-qualified member names. Additionally, retrieval grids must be constructed in a particular format: the POV is on the top row, followed by a well-formed grid. You may have gaps between rows in the retrieval grid.

Setting up a Dodeca HFM Connection

An HFM connection is setup almost exactly the same as an Essbase connection is setup. In Dodeca, create a new Essbase connection. The essential parameters to set are the ServletPath, Server, and Application.

The ServletPath is the URL to the server/port with the Dodeca HFM Connector installed. Assuming it is installed server dodeca-hfm on the default port, the value for this setting will be http://dodeca-hfm:8080/.

The value for Server should be your HFM Cluster name (as opposed to the server itself). For example, this value will often be HFMCluster or whatever the value from your HFM cluster configuration is.

The value for Application should be the name of the application, such as COMMA4DIM.

You are not required, but likely will want to set the Username and Password fields to an admin-level user so that you can test the connection.

After setting up an HFM connection, you can use the Quick Start Utilities option to Import Dimensions (if you wish) to create Dodeca selectors based on the dimensionalityi of your HFM data source.

Setting up a Dodeca HFM Selector List

You can setup a selector list based on HFM dimensionality by using the EssbaseDelimitedString selector type. The DelimitedString option should contain the name of the dimension. Dodeca will use this to initially populate the selector list, and then fetch children of the expanded nodes as needed. Note: as of Dodeca version 7.7.2, enhancements have been made to the selector lists so that the nodes shown in the list will be able to use the fully-qualified member name "behind the scenes" while showing a "nice name" to the user. It is advised that you upgrade Dodeca if possible.

You may also want to use a SQL command directly against your HFM repository to pull the member names. This can be a challenging endeavor to pull the members from a dimension using SQL. An example is provided in the appendix.

Building a View with HFM Data

Views are setup much the same way as an Essbase view would be setup. The "ExcelEssbase" view type is used, where the Essbase Connection is set to your HFM connection. You can use the View Template Designer to design your view, including retrieving from a blank sheet, zooming in, pivoting, and appylying formatting.

Note that the Dodeca HFM Connector does not support the full ad hoc grid retrieval experience. The connector implements what might be considered 'simple' ad hoc operations, meant to facilitate the template design process but not to necessarily serve as a full ad hoc experience such as you might enjoy in the HFM web interface or Smart View. The versions of zoom in, zoom out, and pivot in particular are somewhat limited.

For instance, the pivot operation will always shift the selected axis one dimension counter-clockwise. For example, pivoting on a member in the POV will move it to the "left" grid area. Pivoting again will move the dimension to the right by one unit. If it is the last dimension in the area, the dimension will be pivoted to the "top" region of the grid. If it’s the last dimenzion in the top region, it will be moved back to the POV.

Appendix

Supported Ad hoc Retrieve Options ("EssProperties")

A typical SOAP XML request from the Dodeca client to an Essbase/HFM servlet (connector) will contain the following XML in its overall request. These options mostly correspond to settings that the user can change in their configuration in front-ends such as Smart View, the classic Excel add-in, or the Dodeca Add-in For Excel.

Not all of these options are supported. Most options correspond to checkable/clickable options in options dialogs for ad hoc plugins.

  ...
  <EssProperties>
    <IndentStyle>3</IndentStyle>
    <MissingTextString>0</MissingTextString>
    <NoAccessString>0</NoAccessString>
    <AliasTable>Default</AliasTable>
    <LatestMemberName/>
    <DrillLevel>1</DrillLevel>
    <SuppressMissing>false</SuppressMissing>
    <SuppressZeros>false</SuppressZeros>
    <SuppressUnderscores>false</SuppressUnderscores>
    <RepeatMemberNames>false</RepeatMemberNames>
    <UseAliases>true</UseAliases>
    <UseBothForRowDimensions>false</UseBothForRowDimensions>
    <SpecifyLatestMember>false</SpecifyLatestMember>
    <IncludeSelection>true</IncludeSelection>
    <SelectedGroup>false</SelectedGroup>
    <SelectionOnly>false</SelectionOnly>
    <SendLevelZeroOnly>false</SendLevelZeroOnly>
    <SendZerosAsMissing>true</SendZerosAsMissing>
    <StrictMode>false</StrictMode>
    <UpdateMode>false</UpdateMode>
    <FreeFormMode>false</FreeFormMode>
    <TemplateRetrieveMode>false</TemplateRetrieveMode>
    <AutoSortRows>false</AutoSortRows>
    <DatalessNavigation>true</DatalessNavigation>
    <HybridAnalysisEnabled>false</HybridAnalysisEnabled>
    <UseSmartLists>false</UseSmartLists>
    <EmptyGridError>false</EmptyGridError>
    <CultureCountryRegion>US</CultureCountryRegion>
    <CultureLanguage>en</CultureLanguage>
  </EssProperties>
  ...

<DatalessNavigation> - ("Navigate without data")

This option is supported. When set to true, the grid will be processed and navigation actions (if any) will be performed (such as zooming in) but the actual data retrieval step will not be performed.

<UseAliases> - "Use aliases"

Specifies that members returned from a retrieve operation should be aliases, not the names qualified with the dimension short name and a pound sign. There are several synthetic alias tables available:

  • NonUnique

  • NonUniqueDescription

  • NonUniqueAndDescription

  • Unique (same as not using any table)

The NonUnique table contains member names that are the same as the normal name but without the dimension prefix (e.g. instead of E#EastRegion.EastSales, the member name is just EastRegion.EastSales).

The NonUniqueDescription table consists of just the description values (such as East Sales in this case).

The NonUniqueAndDescription contains both as you might see in HFM, such as EastRegion.EastSales - East Sales.

Note that retrieving and using an alias table should be the last operation that is perforemd on a grid since the HFM connector needs the fully-qualifed member names in order to perform any retrieve.

Dodeca HFM Connector Grid Parsing Notes

Unlike with Essbase, the Dodeca HFM connector performs the job of interpreting the grid that is submitted to it. At present, the HFM connector assumes that an incoming grid is arranged in a certain way. In particular, the POV is always on the very first row and always starts in the second column. For example, the item below named POV 1 is conceptually located in cell B2 (row 1, column 2).

         +------------------------------------+
         |POV 1   |POV 2    |POV 3   |POV 4   |
         +----------------------------------------------------------------+
                  |Jan      |Feb     |Mar     |Apr     |May     |Jun      |
+-------------------------------------------------------------------------+
|Actual  |EastRegi|
+-----------------+
|Actual  |WestRegi|
+-----------------+

After the POV row, there are one or more rows for the "top" dimension area. Similarly, the "left" dimension area has one or more columns. The location of the top dimension area (Jan, Feb, etc. in this case) always starts after the left area.

Retrieve Directives

The Dodeca HFM connector supports the notion of a "retrieve directive". This is a special flag that is located in the top left corner of the retrieve area and starts with the @ symbol. It let’s you specify special ways to format the response grid or on how to interpret the retrieve grid.

For example, there is a retrieve directive to drop prefixes from HFM member names. Consider the following grid:

[                    ][            S#Actual][              Y#2005][          W#Periodic][...]
[                    ][           P#January]
[             A#Sales][                    ]

A normal retrieve will generate the following result:

[                    ][            S#Actual][              Y#2005][          W#Periodic][...]
[                    ][           P#January]
[             A#Sales][           1,322,379]

However, by including the retrieve directive in the top left corner:

[                  @#][            S#Actual][              Y#2005][          W#Periodic][...]
[                    ][           P#January]
[             A#Sales][                    ]

The returned grid will be the following:

[                    ][              Actual][                2005][            Periodic][...]
[                    ][             January]
[               Sales][           1,322,379]

If you would like to use this particular retrieve directive, you should ensure that it’s the last operation that you perform. This is because the HFM connector needs the fully qualified member names in order to retrieve properly, and when they are dropped the grid is not able to be retrieved again. This retrieve directive can be useful as an easy way to 'clean up' the appearance of a grid before showing it to users.

HFM Selector Backed by SQL DataSet

Query example:

WITH ORDER_IN_LOCAL_HIERARCHY(index_in_local_hierachy, ItemID, ParentID)
AS (
    SELECT
    	0,
    	CHILD.ItemID,
    	LAY.ParentID
    FROM
    	COMMA4DIM_ENTITY_ITEM CHILD,
    	COMMA4DIM_ENTITY_LAYOUT LAY
    WHERE
    	CHILD.ItemID = LAY.ItemID AND LAY.PrevSiblingID = -1

    UNION ALL
    SELECT
    	index_in_local_hierachy + 1, LAY.ItemID, LAY.ParentID
    FROM
    	ORDER_IN_LOCAL_HIERARCHY ML, COMMA4DIM_ENTITY_LAYOUT LAY
    WHERE
    	LAY.PrevSiblingID = ML.ItemID AND
    	LAY.ParentID = ML.ParentID AND
		index_in_local_hierachy < 100
)

SELECT
	PARENT.Label AS PARENT_ID,
	'E#' + ISNULL(PARENT.Label + '.', '') + CHILD.Label AS CHILD_ID,
	CHILD.Label AS CHILD_DISPLAY_NAME,
	ISNULL(DESCR.Description, CHILD.Label) as CHILD_DESCRIPTION,
	CHILD.Label + ISNULL(' - ' + DESCR.Description, '') as CHILD_FULL_DESCRIPTION,
	IIF(CHILD.FirstChildID = -1, ISNULL(Parent.Label + '_', '') + CHILD.Label, CHILD.Label) AS DISTINCT_CHILD,
	IIF(CHILD.FirstChildID = -1, 'Y', 'N') AS IS_LEAF,
	ML.index_in_local_hierachy AS SORT_ORDER
FROM
	ORDER_IN_LOCAL_HIERARCHY ML
	INNER JOIN COMMA4DIM_ENTITY_ITEM CHILD ON ML.ItemID = CHILD.ItemID
	LEFT JOIN COMMA4DIM_ENTITY_DESC DESCR ON CHILD.ItemID = DESCR.ItemID
	LEFT JOIN COMMA4DIM_ENTITY_ITEM PARENT on ML.ParentID = PARENT.ItemID
WHERE
	DESCR.LanguageID = 0 OR LanguageID IS NULL

HFM Connection Test Command-Line Java Program

The connection test program is run from the root directory of your HFM Connector installation, such as the following:

java -cp "./hfmjar/*:./lib/*" com.appliedolap.dodeca.hfm.outline.HfmConnectionTest admin HFMCluster COMMA4DIM

The preceding command is formulated for Linux/Unix specifically, changes may need to be made to the classpath (cp) setting when running on Windows, such as ".\\hfmjar\*;\\lib\\*" (escaped backslashes instead of forward slashes, semi-colon to delimit the folders).

There should be three parameters at the end: the username, the HFM cluster name, and the application name. The HFM cluster name is often "HFMCluster" may be something else in your environment. The program will securely prompt for the password for the given user if possible, falling back to a cleartext password prompt if needed.

The HFM connection test program will only work after your HFM Jar files and reg.properties have been put into place in their proper folders, but you do not need to run the connector itself in order to use the connection test program.

The output from this program may look like the following, indicating a successful run:

(base) Jasons-MBP-2:dodeca-hfm-connector-1.1.5 jasonwjones$ java -cp "./hfmjar/*:./lib/*" com.appliedolap.dodeca.hfm.outline.HfmConnectionTest admin HFMCluster COMMA4DIM
Running HFM connection tester
Password:
Feb 21, 2020 9:20:09 AM com.hyperion.hit.registry.ComponentImpl setFileContent
INFO: WRITE - SETFILECONTENT: Component- SHARED_SERVICES_PRODUCT, File Name- CSSConfig
Feb 21, 2020 9:20:09 AM oracle.EPMAUDITCLIENT
INFO: Client Enable Status false
Feb 21, 2020 9:20:09 AM oracle.EPMAUDITCLIENT
INFO: Audit Client has been created for the product HUB-11.1.2.0
Feb 21, 2020 9:20:09 AM oracle.epm.fm.hssservice.RegistryWrapper getRegistryProperty
SEVERE: Invalid property ServerStrategy for HIT Registry component hfm:EPM:sa.
Feb 21, 2020 9:20:09 AM oracle.epm.fm.domainobject.config.ConfigOM load
INFO: The path to the configuration file location is: dummy/config/hfm/configom.properties.
Feb 21, 2020 9:20:09 AM oracle.epm.fm.domainobject.config.ConfigOM load
WARNING: The system could not find file dummy/config/hfm/configom.properties; using default location instead: /oracle/epm/fm/domainobject/config/configom.properties.
Feb 21, 2020 9:20:10 AM oracle.epm.fm.domainobject.application.SessionOM createSession
INFO:  Session is created with Session id : f3333e5e-17b9-4fa4-80a8-d2e047afc1a4
Default POV: S#Actual.Y#1999.P#[Year].W#<Scenario View>.E#[None].V#<Entity Currency>.A#[None].I#[ICP None].C1#[None].C2#[None].C3#[None].C4#[None]

If you do not see the Default POV value printed at the end, then it is likely you are looking at error output instead.

Version History

Version 1.2.0

This is a major release of the Dodeca HFM Connector. A new grid interpretation and projection engine is now used to interpret grids. This has signnificantly enhanced the types of grids that can be retrieved, the operations that can be performed on them, and the ad hoc options that are supported.

The following ad hoc options are now supported:

  • Indent: none, totals, and subitems are all supported

  • Alias handling: ambiguous member names/aliases can now be interpreted in most cases. When peforming an ad hoc operation such as retrieve, zoom in, keep only, others, the grid engine will not return an alias that would be ambiguous. If a member name/alias would be ambiguous, the dimension name is appended to the name, with parentheses around the dimension name. For example, if a retrieve operation would return a member named [None] (which is ambiguous), then the member in the returned grid would be shown as [None] (Products) (or whatever the dimension is).

  • Drill levels: can now drill to next level, all levels, or bottom level

  • Suppress missing/empty grid error: suppress missing works, as well as the "Empty Grid Error" option, which throws an error if all rows would be suppressed

  • Repeat member names option now works

  • Use both for row dimensions: option now works to show both the member name and its alias in the rows

  • Dataless navigation (navigate without data) now works

Additionally, enhanced alias handling is now used for member queries/selections, such that aliases should now work as expected when used in selector lists and tokens on retrieve ranges.

Version 1.1.12

  • Fixed issue with alias tables not being used properly on retrieve. Available alias tables are now Unique, NonUnique, NonUniqueAndDescription, and NonUniqueDescription. The DefaultTopMember alias has been removed.

  • Cleanup README and fixed several typos

Version 1.1.11

  • Fixed issue with fetching children of a dimension

  • Fixed issue where connector would return wrong alias table values on a get member operation

Version 1.1.10

Expanded "EssProperties" support. The EssProperties are properties that are part of each ad hoc request made between the Dodeca client and the Dodeca HFM connector and generally correspond with options you can set in the Essbase/Ad hoc options dialog.

Supported:

<MissingTextString>0</MissingTextString>
<AliasTable>Default</AliasTable>
<DrillLevel>1</DrillLevel>
<SuppressMissing>false</SuppressMissing>
<SuppressUnderscores>false</SuppressUnderscores>
<IncludeSelection>true</IncludeSelection>
<DatalessNavigation>true</DatalessNavigation>
<UseAliases>true</UseAliases>

You may now specify custom text to display for #Missing cells. You can choose to Use Aliases and choose one of the synthetic alias tables for your terminal retrieve operation. The drill levels of next level (children), bottom level (level 0 descendants), and all levels (descendants) are support for zoom in operations. Suppress missing is now available as an option as well as suppress underscores. The "include selection" option is honored, as well as dataless navigation.

If a suppress missing results in no rows of data, an exception will be thrown indicating that where was no data. Enhanced support for empty grids is targetted for a future release (where the user can choose to toggle the empty grid error or not, resulting in either the exception or just a grid with rows of data on it).

Rudimentary zoom out support has been added (zooms a single member to its parent, if any).

Not Supported/No Effect:

<EmptyGridError>false</EmptyGridError>
<SuppressZeros>false</SuppressZeros>
<IndentStyle>3</IndentStyle>
<NoAccessString>0</NoAccessString>
<LatestMemberName/>
<RepeatMemberNames>false</RepeatMemberNames>
<UseBothForRowDimensions>false</UseBothForRowDimensions>
<SpecifyLatestMember>false</SpecifyLatestMember>
<SelectedGroup>false</SelectedGroup>
<SelectionOnly>false</SelectionOnly>
<SendLevelZeroOnly>false</SendLevelZeroOnly>
<SendZerosAsMissing>true</SendZerosAsMissing>
<StrictMode>false</StrictMode>
<UpdateMode>false</UpdateMode>
<FreeFormMode>false</FreeFormMode>
<TemplateRetrieveMode>false</TemplateRetrieveMode>
<AutoSortRows>false</AutoSortRows>
<HybridAnalysisEnabled>false</HybridAnalysisEnabled>
<UseSmartLists>false</UseSmartLists>
<CultureCountryRegion>US</CultureCountryRegion>
<CultureLanguage>en</CultureLanguage>

Version 1.1.9

  • New outline read algorithm handles deep 'shared' hierarchies in HFM application metadata (outline). For example, you might have an Account dimension that looks like this (a standard Account dimension from COMMA4DIM):

    Account                                                         g1,l7   	 {NonUniqueAndDescription=Account, Unique=A#Account, NonUnique=Account}
        A#[None]                                                    g2,l0   	 {NonUniqueAndDescription=[None], Unique=A#[None], NonUnique=[None]}
        A#NetProfit                                                 g2,l6   	 {NonUniqueAndDescription=NetProfit, Unique=A#NetProfit, NonUnique=NetProfit}
            A#IncomeBeforeTaxes                                     g3,l5   	 {NonUniqueAndDescription=IncomeBeforeTaxes, Unique=A#IncomeBeforeTaxes, NonUnique=IncomeBeforeTaxes}
                A#OperatingIncome                                   g4,l4   	 {NonUniqueAndDescription=OperatingIncome, Unique=A#OperatingIncome, NonUnique=OperatingIncome}
                    A#GrossMargin                                   g5,l2   	 {NonUniqueAndDescription=GrossMargin, Unique=A#GrossMargin, NonUnique=GrossMargin}
                        A#TotalRevenues                             g6,l1   	 {NonUniqueAndDescription=TotalRevenues, Unique=A#TotalRevenues, NonUnique=TotalRevenues}
                            A#Sales                                 g7,l0   	 {NonUniqueAndDescription=Sales, Unique=A#Sales, NonUnique=Sales}
                            A#SalesInterco                          g7,l0   	 {NonUniqueAndDescription=SalesInterco, Unique=A#SalesInterco, NonUnique=SalesInterco}
                            A#OtherRevenues                         g7,l0   	 {NonUniqueAndDescription=OtherRevenues, Unique=A#OtherRevenues, NonUnique=OtherRevenues}
                            A#SalesDiscounts                        g7,l0   	 {NonUniqueAndDescription=SalesDiscounts, Unique=A#SalesDiscounts, NonUnique=SalesDiscounts}
                            A#SalesReturns                          g7,l0   	 {NonUniqueAndDescription=SalesReturns, Unique=A#SalesReturns, NonUnique=SalesReturns}
                            A#NewAccount                            g7,l0   	 {NonUniqueAndDescription=NewAccount, Unique=A#NewAccount, NonUnique=NewAccount}
                        A#IntercoDiffPL                             g6,l0   	 {NonUniqueAndDescription=IntercoDiffPL, Unique=A#IntercoDiffPL, NonUnique=IntercoDiffPL}
                        A#COGS                                      g6,l1   	 {NonUniqueAndDescription=COGS, Unique=A#COGS, NonUnique=COGS}
                            A#Purchases                             g7,l0   	 {NonUniqueAndDescription=Purchases, Unique=A#Purchases, NonUnique=Purchases}
                            A#PurchasesInterco                      g7,l0   	 {NonUniqueAndDescription=PurchasesInterco, Unique=A#PurchasesInterco, NonUnique=PurchasesInterco}
                            A#OtherCosts(d)                         g7,l0   	 {NonUniqueAndDescription=OtherCosts(d), Unique=A#OtherCosts(d), NonUnique=OtherCosts(d)}
                            A#LaborCost                             g7,l0   	 {NonUniqueAndDescription=LaborCost, Unique=A#LaborCost, NonUnique=LaborCost}
                    A#OperatingExpenses                             g5,l3   	 {NonUniqueAndDescription=OperatingExpenses, Unique=A#OperatingExpenses, NonUnique=OperatingExpenses}
                        A#DirectCosts                               g6,l2   	 {NonUniqueAndDescription=DirectCosts, Unique=A#DirectCosts, NonUnique=DirectCosts}
                            A#TotalCompensation                     g7,l1   	 {NonUniqueAndDescription=TotalCompensation, Unique=A#TotalCompensation, NonUnique=TotalCompensation}
                                A#Salaries                          g8,l0   	 {NonUniqueAndDescription=Salaries, Unique=A#Salaries, NonUnique=Salaries}
                                A#Salaries_Temp                     g8,l0   	 {NonUniqueAndDescription=Salaries_Temp, Unique=A#Salaries_Temp, NonUnique=Salaries_Temp}
                                A#PayrollTax                        g8,l0   	 {NonUniqueAndDescription=PayrollTax, Unique=A#PayrollTax, NonUnique=PayrollTax}
                            A#ProfessionalSvcs                      g7,l1   	 {NonUniqueAndDescription=ProfessionalSvcs, Unique=A#ProfessionalSvcs, NonUnique=ProfessionalSvcs}
                                A#Legal                             g8,l0   	 {NonUniqueAndDescription=Legal, Unique=A#Legal, NonUnique=Legal}
                                A#Janitorial                        g8,l0   	 {NonUniqueAndDescription=Janitorial, Unique=A#Janitorial, NonUnique=Janitorial}
                                A#Software                          g8,l0   	 {NonUniqueAndDescription=Software, Unique=A#Software, NonUnique=Software}
                                A#Advertising                       g8,l0   	 {NonUniqueAndDescription=Advertising, Unique=A#Advertising, NonUnique=Advertising}
                            A#TravelandEnt                          g7,l1   	 {NonUniqueAndDescription=TravelandEnt, Unique=A#TravelandEnt, NonUnique=TravelandEnt}
                                A#Travel                            g8,l0   	 {NonUniqueAndDescription=Travel, Unique=A#Travel, NonUnique=Travel}
                                A#Meals                             g8,l0   	 {NonUniqueAndDescription=Meals, Unique=A#Meals, NonUnique=Meals}
                                A#Entertainment                     g8,l0   	 {NonUniqueAndDescription=Entertainment, Unique=A#Entertainment, NonUnique=Entertainment}
                            A#Administrative                        g7,l1   	 {NonUniqueAndDescription=Administrative, Unique=A#Administrative, NonUnique=Administrative}
                                A#Telephone                         g8,l0   	 {NonUniqueAndDescription=Telephone, Unique=A#Telephone, NonUnique=Telephone}
                                A#Utilities                         g8,l0   	 {NonUniqueAndDescription=Utilities, Unique=A#Utilities, NonUnique=Utilities}
                                A#Maintenance                       g8,l0   	 {NonUniqueAndDescription=Maintenance, Unique=A#Maintenance, NonUnique=Maintenance}
                                A#MaintenanceAllocated              g8,l0   	 {NonUniqueAndDescription=MaintenanceAllocated, Unique=A#MaintenanceAllocated, NonUnique=MaintenanceAllocated}
                                A#RentBuilding                      g8,l0   	 {NonUniqueAndDescription=RentBuilding, Unique=A#RentBuilding, NonUnique=RentBuilding}
                                A#RentBldgAllocated                 g8,l0   	 {NonUniqueAndDescription=RentBldgAllocated, Unique=A#RentBldgAllocated, NonUnique=RentBldgAllocated}
                                A#RentEquipment                     g8,l0   	 {NonUniqueAndDescription=RentEquipment, Unique=A#RentEquipment, NonUnique=RentEquipment}
                                A#OfficeSupplies                    g8,l0   	 {NonUniqueAndDescription=OfficeSupplies, Unique=A#OfficeSupplies, NonUnique=OfficeSupplies}
                                A#Warranty                          g8,l0   	 {NonUniqueAndDescription=Warranty, Unique=A#Warranty, NonUnique=Warranty}
                                A#PatentAmort                       g8,l0   	 {NonUniqueAndDescription=PatentAmort, Unique=A#PatentAmort, NonUnique=PatentAmort}
                        A#TotalDeprAmort                            g6,l2   	 {NonUniqueAndDescription=TotalDeprAmort, Unique=A#TotalDeprAmort, NonUnique=TotalDeprAmort}
                            A#Depreciation                          g7,l1   	 {NonUniqueAndDescription=Depreciation, Unique=A#Depreciation, NonUnique=Depreciation}
                                A#TransportationDepr                g8,l0   	 {NonUniqueAndDescription=TransportationDepr, Unique=A#TransportationDepr, NonUnique=TransportationDepr}
                                A#BuildingDepr                      g8,l0   	 {NonUniqueAndDescription=BuildingDepr, Unique=A#BuildingDepr, NonUnique=BuildingDepr}
                            A#Amortization                          g7,l1   	 {NonUniqueAndDescription=Amortization, Unique=A#Amortization, NonUnique=Amortization}
                                A#GoodwillAmort                     g8,l0   	 {NonUniqueAndDescription=GoodwillAmort, Unique=A#GoodwillAmort, NonUnique=GoodwillAmort}
                A#InterestInc(Exp)                                  g4,l0   	 {NonUniqueAndDescription=InterestInc(Exp), Unique=A#InterestInc(Exp), NonUnique=InterestInc(Exp)}
            A#Taxes                                                 g3,l0   	 {NonUniqueAndDescription=Taxes, Unique=A#Taxes, NonUnique=Taxes}
        A#TotalAssets                                               g2,l4   	 {NonUniqueAndDescription=TotalAssets, Unique=A#TotalAssets, NonUnique=TotalAssets}
            A#TotalShortTermAssets                                  g3,l1   	 {NonUniqueAndDescription=TotalShortTermAssets, Unique=A#TotalShortTermAssets, NonUnique=TotalShortTermAssets}
                A#Cash                                              g4,l0   	 {NonUniqueAndDescription=Cash, Unique=A#Cash, NonUnique=Cash}
                A#ShortTermRec                                      g4,l0   	 {NonUniqueAndDescription=ShortTermRec, Unique=A#ShortTermRec, NonUnique=ShortTermRec}
                A#ShortTermRecInterco                               g4,l0   	 {NonUniqueAndDescription=ShortTermRecInterco, Unique=A#ShortTermRecInterco, NonUnique=ShortTermRecInterco}
                A#Inventories                                       g4,l0   	 {NonUniqueAndDescription=Inventories, Unique=A#Inventories, NonUnique=Inventories}
                A#ShortTermInvest                                   g4,l0   	 {NonUniqueAndDescription=ShortTermInvest, Unique=A#ShortTermInvest, NonUnique=ShortTermInvest}
            A#TotalLongTermAssets                                   g3,l3   	 {NonUniqueAndDescription=TotalLongTermAssets, Unique=A#TotalLongTermAssets, NonUnique=TotalLongTermAssets}
                A#TangibleAssetsNet                                 g4,l2   	 {NonUniqueAndDescription=TangibleAssetsNet, Unique=A#TangibleAssetsNet, NonUnique=TangibleAssetsNet}
                    A#TangibleAssets                                g5,l1   	 {NonUniqueAndDescription=TangibleAssets, Unique=A#TangibleAssets, NonUnique=TangibleAssets}
                        A#Computer                                  g6,l0   	 {NonUniqueAndDescription=Computer, Unique=A#Computer, NonUnique=Computer}
                        A#Building                                  g6,l0   	 {NonUniqueAndDescription=Building, Unique=A#Building, NonUnique=Building}
                        A#Land                                      g6,l0   	 {NonUniqueAndDescription=Land, Unique=A#Land, NonUnique=Land}
                        A#Equipment                                 g6,l0   	 {NonUniqueAndDescription=Equipment, Unique=A#Equipment, NonUnique=Equipment}
                        A#Transportation                            g6,l0   	 {NonUniqueAndDescription=Transportation, Unique=A#Transportation, NonUnique=Transportation}
                        A#Fixtures                                  g6,l0   	 {NonUniqueAndDescription=Fixtures, Unique=A#Fixtures, NonUnique=Fixtures}
                    A#AccumDepr                                     g5,l0   	 {NonUniqueAndDescription=AccumDepr, Unique=A#AccumDepr, NonUnique=AccumDepr}
                A#Investments                                       g4,l0   	 {NonUniqueAndDescription=Investments, Unique=A#Investments, NonUnique=Investments}
                A#LongTermRec                                       g4,l0   	 {NonUniqueAndDescription=LongTermRec, Unique=A#LongTermRec, NonUnique=LongTermRec}
                A#LongTermRecInterco                                g4,l0   	 {NonUniqueAndDescription=LongTermRecInterco, Unique=A#LongTermRecInterco, NonUnique=LongTermRecInterco}
            A#IntercoDiffBS                                         g3,l0   	 {NonUniqueAndDescription=IntercoDiffBS, Unique=A#IntercoDiffBS, NonUnique=IntercoDiffBS}
        A#TotalLiabEquity                                           g2,l3   	 {NonUniqueAndDescription=TotalLiabEquity, Unique=A#TotalLiabEquity, NonUnique=TotalLiabEquity}
            A#TotalLiabilities                                      g3,l2   	 {NonUniqueAndDescription=TotalLiabilities, Unique=A#TotalLiabilities, NonUnique=TotalLiabilities}
                A#TotalShortTermLiab                                g4,l1   	 {NonUniqueAndDescription=TotalShortTermLiab, Unique=A#TotalShortTermLiab, NonUnique=TotalShortTermLiab}
                    A#BankOverdraft                                 g5,l0   	 {NonUniqueAndDescription=BankOverdraft, Unique=A#BankOverdraft, NonUnique=BankOverdraft}
                    A#ShortTermPay                                  g5,l0   	 {NonUniqueAndDescription=ShortTermPay, Unique=A#ShortTermPay, NonUnique=ShortTermPay}
                    A#ShortTermPayInterco                           g5,l0   	 {NonUniqueAndDescription=ShortTermPayInterco, Unique=A#ShortTermPayInterco, NonUnique=ShortTermPayInterco}
                    A#ShortTermDebt                                 g5,l0   	 {NonUniqueAndDescription=ShortTermDebt, Unique=A#ShortTermDebt, NonUnique=ShortTermDebt}
                    A#AccruedTax                                    g5,l0   	 {NonUniqueAndDescription=AccruedTax, Unique=A#AccruedTax, NonUnique=AccruedTax}
                A#TotalLongTermLiab                                 g4,l1   	 {NonUniqueAndDescription=TotalLongTermLiab, Unique=A#TotalLongTermLiab, NonUnique=TotalLongTermLiab}
                    A#LongTermLoans                                 g5,l0   	 {NonUniqueAndDescription=LongTermLoans, Unique=A#LongTermLoans, NonUnique=LongTermLoans}
                    A#LongTermPay                                   g5,l0   	 {NonUniqueAndDescription=LongTermPay, Unique=A#LongTermPay, NonUnique=LongTermPay}
                    A#LongTermPayInterco                            g5,l0   	 {NonUniqueAndDescription=LongTermPayInterco, Unique=A#LongTermPayInterco, NonUnique=LongTermPayInterco}
                    A#Provisions                                    g5,l0   	 {NonUniqueAndDescription=Provisions, Unique=A#Provisions, NonUnique=Provisions}
            A#TotalEquity                                           g3,l1   	 {NonUniqueAndDescription=TotalEquity, Unique=A#TotalEquity, NonUnique=TotalEquity}
                A#CapitalStock                                      g4,l0   	 {NonUniqueAndDescription=CapitalStock, Unique=A#CapitalStock, NonUnique=CapitalStock}
                A#PaidinCapital                                     g4,l0   	 {NonUniqueAndDescription=PaidinCapital, Unique=A#PaidinCapital, NonUnique=PaidinCapital}
                A#Dividends                                         g4,l0   	 {NonUniqueAndDescription=Dividends, Unique=A#Dividends, NonUnique=Dividends}
                A#RetainedEarnings                                  g4,l0   	 {NonUniqueAndDescription=RetainedEarnings, Unique=A#RetainedEarnings, NonUnique=RetainedEarnings}
                A#TranslationDiff                                   g4,l0   	 {NonUniqueAndDescription=TranslationDiff, Unique=A#TranslationDiff, NonUnique=TranslationDiff}
                A#Profit                                            g4,l0   	 {NonUniqueAndDescription=Profit, Unique=A#Profit, NonUnique=Profit}
                A#Surplus                                           g4,l0   	 {NonUniqueAndDescription=Surplus, Unique=A#Surplus, NonUnique=Surplus}
        A#OtherInfo                                                 g2,l2   	 {NonUniqueAndDescription=OtherInfo, Unique=A#OtherInfo, NonUnique=OtherInfo}
            A#Headcount                                             g3,l0   	 {NonUniqueAndDescription=Headcount, Unique=A#Headcount, NonUnique=Headcount}
            A#UnitsSold                                             g3,l0   	 {NonUniqueAndDescription=UnitsSold, Unique=A#UnitsSold, NonUnique=UnitsSold}
            A#Price                                                 g3,l0   	 {NonUniqueAndDescription=Price, Unique=A#Price, NonUnique=Price}
            A#AverageProfit                                         g3,l0   	 {NonUniqueAndDescription=AverageProfit, Unique=A#AverageProfit, NonUnique=AverageProfit}
            A#AverageSales                                          g3,l0   	 {NonUniqueAndDescription=AverageSales, Unique=A#AverageSales, NonUnique=AverageSales}
            A#SalesUnitBacklog                                      g3,l0   	 {NonUniqueAndDescription=SalesUnitBacklog, Unique=A#SalesUnitBacklog, NonUnique=SalesUnitBacklog}
            A#RunAdjFactors                                         g3,l0   	 {NonUniqueAndDescription=RunAdjFactors, Unique=A#RunAdjFactors, NonUnique=RunAdjFactors}
            A#RunTopDownAlloc                                       g3,l0   	 {NonUniqueAndDescription=RunTopDownAlloc, Unique=A#RunTopDownAlloc, NonUnique=RunTopDownAlloc}
            A#Rates                                                 g3,l1   	 {NonUniqueAndDescription=Rates, Unique=A#Rates, NonUnique=Rates}
                A#SalaryRate                                        g4,l0   	 {NonUniqueAndDescription=SalaryRate, Unique=A#SalaryRate, NonUnique=SalaryRate}
                A#OfficeSupplyRate                                  g4,l0   	 {NonUniqueAndDescription=OfficeSupplyRate, Unique=A#OfficeSupplyRate, NonUnique=OfficeSupplyRate}
                A#TravelExpRate                                     g4,l0   	 {NonUniqueAndDescription=TravelExpRate, Unique=A#TravelExpRate, NonUnique=TravelExpRate}
                A#PurchaseRate                                      g4,l0   	 {NonUniqueAndDescription=PurchaseRate, Unique=A#PurchaseRate, NonUnique=PurchaseRate}
                A#LaborCostRate                                     g4,l0   	 {NonUniqueAndDescription=LaborCostRate, Unique=A#LaborCostRate, NonUnique=LaborCostRate}
                A#BaseSalary                                        g4,l0   	 {NonUniqueAndDescription=BaseSalary, Unique=A#BaseSalary, NonUnique=BaseSalary}
                A#MeritIncrease                                     g4,l0   	 {NonUniqueAndDescription=MeritIncrease, Unique=A#MeritIncrease, NonUnique=MeritIncrease}
                A#IncentiveRate                                     g4,l0   	 {NonUniqueAndDescription=IncentiveRate, Unique=A#IncentiveRate, NonUnique=IncentiveRate}
                A#SocialSecurityRate                                g4,l0   	 {NonUniqueAndDescription=SocialSecurityRate, Unique=A#SocialSecurityRate, NonUnique=SocialSecurityRate}
                A#PayrollTaxRate                                    g4,l0   	 {NonUniqueAndDescription=PayrollTaxRate, Unique=A#PayrollTaxRate, NonUnique=PayrollTaxRate}
                A#GrowthRate                                        g4,l0   	 {NonUniqueAndDescription=GrowthRate, Unique=A#GrowthRate, NonUnique=GrowthRate}
                A#Consol_Status                                     g4,l0   	 {NonUniqueAndDescription=Consol_Status, Unique=A#Consol_Status, NonUnique=Consol_Status}
                A#TaxRate                                           g4,l0   	 {NonUniqueAndDescription=TaxRate, Unique=A#TaxRate, NonUnique=TaxRate}
                A#PriceAdjRate                                      g4,l0   	 {NonUniqueAndDescription=PriceAdjRate, Unique=A#PriceAdjRate, NonUnique=PriceAdjRate}
                A#COGSDecrRate                                      g4,l0   	 {NonUniqueAndDescription=COGSDecrRate, Unique=A#COGSDecrRate, NonUnique=COGSDecrRate}
                A#PctGrowth                                         g4,l0   	 {NonUniqueAndDescription=PctGrowth, Unique=A#PctGrowth, NonUnique=PctGrowth}
                A#AvgGrowth                                         g4,l0   	 {NonUniqueAndDescription=AvgGrowth, Unique=A#AvgGrowth, NonUnique=AvgGrowth}
                A#UnitPctIncrease                                   g4,l0   	 {NonUniqueAndDescription=UnitPctIncrease, Unique=A#UnitPctIncrease, NonUnique=UnitPctIncrease}
            A#Functions                                             g3,l1   	 {NonUniqueAndDescription=Functions, Unique=A#Functions, NonUnique=Functions}
                A#Spread                                            g4,l0   	 {NonUniqueAndDescription=Spread, Unique=A#Spread, NonUnique=Spread}
                A#Allocate                                          g4,l0   	 {NonUniqueAndDescription=Allocate, Unique=A#Allocate, NonUnique=Allocate}
            A#DynamicAccounts                                       g3,l1   	 {NonUniqueAndDescription=DynamicAccounts, Unique=A#DynamicAccounts, NonUnique=DynamicAccounts}
                A#MarginPct                                         g4,l0   	 {NonUniqueAndDescription=MarginPct, Unique=A#MarginPct, NonUnique=MarginPct}
                A#DiscountPct                                       g4,l0   	 {NonUniqueAndDescription=DiscountPct, Unique=A#DiscountPct, NonUnique=DiscountPct}
                A#ReturnPct                                         g4,l0   	 {NonUniqueAndDescription=ReturnPct, Unique=A#ReturnPct, NonUnique=ReturnPct}
        A#ExchangeRates                                             g2,l1   	 {NonUniqueAndDescription=ExchangeRates, Unique=A#ExchangeRates, NonUnique=ExchangeRates}
            A#ClosingRate                                           g3,l0   	 {NonUniqueAndDescription=ClosingRate, Unique=A#ClosingRate, NonUnique=ClosingRate}
            A#AverageRate                                           g3,l0   	 {NonUniqueAndDescription=AverageRate, Unique=A#AverageRate, NonUnique=AverageRate}
            A#OpeningRate                                           g3,l0   	 {NonUniqueAndDescription=OpeningRate, Unique=A#OpeningRate, NonUnique=OpeningRate}
            A#CustomRate                                            g3,l0   	 {NonUniqueAndDescription=CustomRate, Unique=A#CustomRate, NonUnique=CustomRate}
            A#HistoricRate1                                         g3,l0   	 {NonUniqueAndDescription=HistoricRate1, Unique=A#HistoricRate1, NonUnique=HistoricRate1}
            A#HistoricRate2                                         g3,l0   	 {NonUniqueAndDescription=HistoricRate2, Unique=A#HistoricRate2, NonUnique=HistoricRate2}
        A#CostAllocation                                            g2,l1   	 {NonUniqueAndDescription=CostAllocation, Unique=A#CostAllocation, NonUnique=CostAllocation}
            A#AllocatedCosts1                                       g3,l0   	 {NonUniqueAndDescription=AllocatedCosts1, Unique=A#AllocatedCosts1, NonUnique=AllocatedCosts1}
            A#AllocatedCosts2                                       g3,l0   	 {NonUniqueAndDescription=AllocatedCosts2, Unique=A#AllocatedCosts2, NonUnique=AllocatedCosts2}
        A#CashFlow                                                  g2,l3   	 {NonUniqueAndDescription=CashFlow, Unique=A#CashFlow, NonUnique=CashFlow}
            A#CFTotal                                               g3,l2   	 {NonUniqueAndDescription=CFTotal, Unique=A#CFTotal, NonUnique=CFTotal}
                A#CFOperations                                      g4,l1   	 {NonUniqueAndDescription=CFOperations, Unique=A#CFOperations, NonUnique=CFOperations}
                    A#CFIncome                                      g5,l0   	 {NonUniqueAndDescription=CFIncome, Unique=A#CFIncome, NonUnique=CFIncome}
                    A#CFDepr                                        g5,l0   	 {NonUniqueAndDescription=CFDepr, Unique=A#CFDepr, NonUnique=CFDepr}
                    A#CFDefTax                                      g5,l0   	 {NonUniqueAndDescription=CFDefTax, Unique=A#CFDefTax, NonUnique=CFDefTax}
                    A#CFAcctsRec                                    g5,l0   	 {NonUniqueAndDescription=CFAcctsRec, Unique=A#CFAcctsRec, NonUnique=CFAcctsRec}
                    A#CFInven                                       g5,l0   	 {NonUniqueAndDescription=CFInven, Unique=A#CFInven, NonUnique=CFInven}
                    A#CFAcctsPay                                    g5,l0   	 {NonUniqueAndDescription=CFAcctsPay, Unique=A#CFAcctsPay, NonUnique=CFAcctsPay}
                    A#CFOthOper                                     g5,l0   	 {NonUniqueAndDescription=CFOthOper, Unique=A#CFOthOper, NonUnique=CFOthOper}
                A#CFInvesting                                       g4,l1   	 {NonUniqueAndDescription=CFInvesting, Unique=A#CFInvesting, NonUnique=CFInvesting}
                    A#CFPPE                                         g5,l0   	 {NonUniqueAndDescription=CFPPE, Unique=A#CFPPE, NonUnique=CFPPE}
                    A#CFInvestNR                                    g5,l0   	 {NonUniqueAndDescription=CFInvestNR, Unique=A#CFInvestNR, NonUnique=CFInvestNR}
                    A#CFShortTInvest                                g5,l0   	 {NonUniqueAndDescription=CFShortTInvest, Unique=A#CFShortTInvest, NonUnique=CFShortTInvest}
                    A#CFOtherInvest                                 g5,l0   	 {NonUniqueAndDescription=CFOtherInvest, Unique=A#CFOtherInvest, NonUnique=CFOtherInvest}
                A#CFFinancing                                       g4,l1   	 {NonUniqueAndDescription=CFFinancing, Unique=A#CFFinancing, NonUnique=CFFinancing}
                    A#CFSTDebt                                      g5,l0   	 {NonUniqueAndDescription=CFSTDebt, Unique=A#CFSTDebt, NonUnique=CFSTDebt}
                    A#CFLTDebt                                      g5,l0   	 {NonUniqueAndDescription=CFLTDebt, Unique=A#CFLTDebt, NonUnique=CFLTDebt}
                    A#CFLTOblig                                     g5,l0   	 {NonUniqueAndDescription=CFLTOblig, Unique=A#CFLTOblig, NonUnique=CFLTOblig}
                    A#CFEquity                                      g5,l0   	 {NonUniqueAndDescription=CFEquity, Unique=A#CFEquity, NonUnique=CFEquity}
                    A#CFDividends                                   g5,l0   	 {NonUniqueAndDescription=CFDividends, Unique=A#CFDividends, NonUnique=CFDividends}
                    A#CFOtherFin                                    g5,l0   	 {NonUniqueAndDescription=CFOtherFin, Unique=A#CFOtherFin, NonUnique=CFOtherFin}
                A#CFFX                                              g4,l0   	 {NonUniqueAndDescription=CFFX, Unique=A#CFFX, NonUnique=CFFX}
        A#KeyMetrics                                                g2,l1   	 {NonUniqueAndDescription=KeyMetrics, Unique=A#KeyMetrics, NonUnique=KeyMetrics}
            A#EBIT                                                  g3,l0   	 {NonUniqueAndDescription=EBIT, Unique=A#EBIT, NonUnique=EBIT}
            A#EBITDA                                                g3,l0   	 {NonUniqueAndDescription=EBITDA, Unique=A#EBITDA, NonUnique=EBITDA}
            A#ROS                                                   g3,l0   	 {NonUniqueAndDescription=ROS, Unique=A#ROS, NonUnique=ROS}
            A#ROA                                                   g3,l0   	 {NonUniqueAndDescription=ROA, Unique=A#ROA, NonUnique=ROA}
            A#CurrentRatio                                          g3,l0   	 {NonUniqueAndDescription=CurrentRatio, Unique=A#CurrentRatio, NonUnique=CurrentRatio}
            A#DebtRatio                                             g3,l0   	 {NonUniqueAndDescription=DebtRatio, Unique=A#DebtRatio, NonUnique=DebtRatio}
            A#InterestCovRatio                                      g3,l0   	 {NonUniqueAndDescription=InterestCovRatio, Unique=A#InterestCovRatio, NonUnique=InterestCovRatio}
            A#Sales_Validation                                      g3,l0   	 {NonUniqueAndDescription=Sales_Validation, Unique=A#Sales_Validation, NonUnique=Sales_Validation}
            A#Sales_Control_Total                                   g3,l0   	 {NonUniqueAndDescription=Sales_Control_Total, Unique=A#Sales_Control_Total, NonUnique=Sales_Control_Total}
            A#Balancing_Validation                                  g3,l0   	 {NonUniqueAndDescription=Balancing_Validation, Unique=A#Balancing_Validation, NonUnique=Balancing_Validation}
        A#Validation                                                g2,l1   	 {NonUniqueAndDescription=Validation, Unique=A#Validation, NonUnique=Validation}
            A#Surplus                                               g3,l0 * 	 {NonUniqueAndDescription=Surplus, Unique=A#Surplus, NonUnique=Surplus}
            A#ICMatch

Let’s then say that that the entire A#CashFlow member is 'added' underneath A#Balancing_Validation — in other words, a deep (more than one level) shared hierarchy exists here. The Dodeca HFM Connector will 'stub' this outline so that only a single share appears to exist:

(rest of outline above A#CashFlow omitted)
	A#CashFlow                                                  g2,l3   	 {NonUniqueAndDescription=CashFlow, Unique=A#CashFlow, NonUnique=CashFlow}
       A#CFTotal                                               g3,l2   	 {NonUniqueAndDescription=CFTotal, Unique=A#CFTotal, NonUnique=CFTotal}
           A#CFOperations                                      g4,l1   	 {NonUniqueAndDescription=CFOperations, Unique=A#CFOperations, NonUnique=CFOperations}
               A#CFIncome                                      g5,l0   	 {NonUniqueAndDescription=CFIncome, Unique=A#CFIncome, NonUnique=CFIncome}
               A#CFDepr                                        g5,l0   	 {NonUniqueAndDescription=CFDepr, Unique=A#CFDepr, NonUnique=CFDepr}
               A#CFDefTax                                      g5,l0   	 {NonUniqueAndDescription=CFDefTax, Unique=A#CFDefTax, NonUnique=CFDefTax}
               A#CFAcctsRec                                    g5,l0   	 {NonUniqueAndDescription=CFAcctsRec, Unique=A#CFAcctsRec, NonUnique=CFAcctsRec}
               A#CFInven                                       g5,l0   	 {NonUniqueAndDescription=CFInven, Unique=A#CFInven, NonUnique=CFInven}
               A#CFAcctsPay                                    g5,l0   	 {NonUniqueAndDescription=CFAcctsPay, Unique=A#CFAcctsPay, NonUnique=CFAcctsPay}
               A#CFOthOper                                     g5,l0   	 {NonUniqueAndDescription=CFOthOper, Unique=A#CFOthOper, NonUnique=CFOthOper}
           A#CFInvesting                                       g4,l1   	 {NonUniqueAndDescription=CFInvesting, Unique=A#CFInvesting, NonUnique=CFInvesting}
               A#CFPPE                                         g5,l0   	 {NonUniqueAndDescription=CFPPE, Unique=A#CFPPE, NonUnique=CFPPE}
               A#CFInvestNR                                    g5,l0   	 {NonUniqueAndDescription=CFInvestNR, Unique=A#CFInvestNR, NonUnique=CFInvestNR}
               A#CFShortTInvest                                g5,l0   	 {NonUniqueAndDescription=CFShortTInvest, Unique=A#CFShortTInvest, NonUnique=CFShortTInvest}
               A#CFOtherInvest                                 g5,l0   	 {NonUniqueAndDescription=CFOtherInvest, Unique=A#CFOtherInvest, NonUnique=CFOtherInvest}
           A#CFFinancing                                       g4,l1   	 {NonUniqueAndDescription=CFFinancing, Unique=A#CFFinancing, NonUnique=CFFinancing}
               A#CFSTDebt                                      g5,l0   	 {NonUniqueAndDescription=CFSTDebt, Unique=A#CFSTDebt, NonUnique=CFSTDebt}
               A#CFLTDebt                                      g5,l0   	 {NonUniqueAndDescription=CFLTDebt, Unique=A#CFLTDebt, NonUnique=CFLTDebt}
               A#CFLTOblig                                     g5,l0   	 {NonUniqueAndDescription=CFLTOblig, Unique=A#CFLTOblig, NonUnique=CFLTOblig}
               A#CFEquity                                      g5,l0   	 {NonUniqueAndDescription=CFEquity, Unique=A#CFEquity, NonUnique=CFEquity}
               A#CFDividends                                   g5,l0   	 {NonUniqueAndDescription=CFDividends, Unique=A#CFDividends, NonUnique=CFDividends}
               A#CFOtherFin                                    g5,l0   	 {NonUniqueAndDescription=CFOtherFin, Unique=A#CFOtherFin, NonUnique=CFOtherFin}
           A#CFFX                                              g4,l0   	 {NonUniqueAndDescription=CFFX, Unique=A#CFFX, NonUnique=CFFX}
   A#KeyMetrics                                                g2,l2   	 {NonUniqueAndDescription=KeyMetrics, Unique=A#KeyMetrics, NonUnique=KeyMetrics}
       A#EBIT                                                  g3,l0   	 {NonUniqueAndDescription=EBIT, Unique=A#EBIT, NonUnique=EBIT}
       A#EBITDA                                                g3,l0   	 {NonUniqueAndDescription=EBITDA, Unique=A#EBITDA, NonUnique=EBITDA}
       A#ROS                                                   g3,l0   	 {NonUniqueAndDescription=ROS, Unique=A#ROS, NonUnique=ROS}
       A#ROA                                                   g3,l0   	 {NonUniqueAndDescription=ROA, Unique=A#ROA, NonUnique=ROA}
       A#CurrentRatio                                          g3,l0   	 {NonUniqueAndDescription=CurrentRatio, Unique=A#CurrentRatio, NonUnique=CurrentRatio}
       A#DebtRatio                                             g3,l0   	 {NonUniqueAndDescription=DebtRatio, Unique=A#DebtRatio, NonUnique=DebtRatio}
       A#InterestCovRatio                                      g3,l0   	 {NonUniqueAndDescription=InterestCovRatio, Unique=A#InterestCovRatio, NonUnique=InterestCovRatio}
       A#Sales_Validation                                      g3,l0   	 {NonUniqueAndDescription=Sales_Validation, Unique=A#Sales_Validation, NonUnique=Sales_Validation}
       A#Sales_Control_Total                                   g3,l0   	 {NonUniqueAndDescription=Sales_Control_Total, Unique=A#Sales_Control_Total, NonUnique=Sales_Control_Total}
       A#Balancing_Validation                                  g3,l1   	 {NonUniqueAndDescription=Balancing_Validation, Unique=A#Balancing_Validation, NonUnique=Balancing_Validation}
           A#CFTotal                                           g4,l0 * 	 {NonUniqueAndDescription=CFTotal, Unique=A#CFTotal, NonUnique=CFTotal}
   A#Validation                                                g2,l1   	 {NonUniqueAndDescription=Validation, Unique=A#Validation, NonUnique=Validation}
       A#Surplus                                               g3,l0 * 	 {NonUniqueAndDescription=Surplus, Unique=A#Surplus, NonUnique=Surplus}
       A#ICMatch

Note the presence of A#CFTotal underneath A#Balancing_Validation. Previously, the members in the shared hierarchy would cause an issue where the Dodeca client couldn’t disambiguate them from the prototype members.

  • Slight change to OutlinePrinter — now requires --password even if you want the program to prompt you to enter a password

Version 1.1.8

  • Member generation (outline depth) is now adjusted for shared members. Previously, the generation coming back from a member request would use the generation of the prototype member. Now, even with shared members, the generation will be for that particular share member’s location in the outline. This should fix issues customers are seeing, for example, in a custom dimension where there is a top-level member named '[None]' with a sibling whose children contain several members, including '[None] again.

  • Some of the synthetic alias tables are removed, including DefaultTopMember and NonUniqueDescription. Both of these tables seem to cause many problems in terms of the chance for aliases to get reused across multiple different members, which causes various issues with selector lists in Dodeca. If you use an alias table for your HFM selector lists, you are encouraged to use NonUniqueAndDescription, which should be unique across the board.

  • Added new outline printer test utility, can be run such as:

    java -cp "./hfmjar/*:./lib/*" com.appliedolap.dodeca.hfm.testing.OutlinePrinter --cluster HFMCluster --application COMMA4DIM --username admin --password Password1

    Can also be run without the password; you will be prompted:

    java -cp "./hfmjar/*:./lib/*" com.appliedolap.dodeca.hfm.testing.OutlinePrinter --cluster HFMCluster --application COMMA4DIM --username admin --password
  • Treatment of "shared" members has been adjusted. Previously, an HFM dimension could contain multiple references to the same member that would appear as multiple hierarchies. This causes problems for Dodeca selector lists/treeviews because the request for children of a given member would always return the children of the 'prototype' member, which may be at a different generation. To address this issue, when an HFM outline is created, the duplicate members are searched for and if they are found, they are converted into a 'stub' member.

For example, consider the following depiction of the Channel dimension from COMMA4DIM:

Channel at g/l 1/3 with parent null
    C3#[None] at g/l 2/0 with parent Channel
    C3#TotalC3 at g/l 2/2 with parent Channel
        C3#TotalChannels at g/l 3/1 with parent C3#TotalC3
            C3#National_Accts at g/l 4/0 with parent C3#TotalChannels
            C3#Distributor_Sales at g/l 4/0 with parent C3#TotalChannels
            C3#Wireless_Accts at g/l 4/0 with parent C3#TotalChannels
            C3#Retail_Direct at g/l 4/0 with parent C3#TotalChannels
            C3#NoChannel at g/l 4/0 with parent C3#TotalChannels
        C3#TotalGrades at g/l 3/1 with parent C3#TotalC3
            C3#Intern at g/l 4/0 with parent C3#TotalGrades
            C3#Junior at g/l 4/0 with parent C3#TotalGrades
            C3#Senior at g/l 4/0 with parent C3#TotalGrades
            C3#Lead at g/l 4/0 with parent C3#TotalGrades
            C3#Manager at g/l 4/0 with parent C3#TotalGrades
            C3#Director at g/l 4/0 with parent C3#TotalGrades
            C3#VicePresident at g/l 4/0 with parent C3#TotalGrades
            C3#Executive at g/l 4/0 with parent C3#TotalGrades
            C3#[None] at g/l 4/0 with parent Channel

In this presentation, the members are printed in their hierarchical order as well as showing generation/level (g/l) information.

Let’s say that this dimension was actually constructed differently, such that we add a "shared" member of C3#Total Channels under C3#TotalGrades as well as another copy under C3#Director. This causes the outline to now present as the following:

Channel at g/l 1/5 with parent null
    C3#[None] at g/l 2/0 with parent Channel
    C3#TotalC3 at g/l 2/4 with parent Channel
        C3#TotalChannels at g/l 3/1 with parent C3#TotalC3
            C3#National_Accts at g/l 4/0 with parent C3#TotalChannels
            C3#Distributor_Sales at g/l 4/0 with parent C3#TotalChannels
            C3#Wireless_Accts at g/l 4/0 with parent C3#TotalChannels
            C3#Retail_Direct at g/l 4/0 with parent C3#TotalChannels
            C3#NoChannel at g/l 4/0 with parent C3#TotalChannels
        C3#TotalGrades at g/l 3/3 with parent C3#TotalC3
            C3#Intern at g/l 4/0 with parent C3#TotalGrades
            C3#Junior at g/l 4/0 with parent C3#TotalGrades
            C3#Senior at g/l 4/0 with parent C3#TotalGrades
            C3#Lead at g/l 4/0 with parent C3#TotalGrades
            C3#Manager at g/l 4/0 with parent C3#TotalGrades
            C3#Director at g/l 4/2 with parent C3#TotalGrades
                C3#TotalChannels at g/l 5/1 with parent C3#TotalC3
                    C3#National_Accts at g/l 4/0 with parent C3#TotalChannels
                    C3#Distributor_Sales at g/l 4/0 with parent C3#TotalChannels
                    C3#Wireless_Accts at g/l 4/0 with parent C3#TotalChannels
                    C3#Retail_Direct at g/l 4/0 with parent C3#TotalChannels
                    C3#NoChannel at g/l 4/0 with parent C3#TotalChannels
            C3#VicePresident at g/l 4/0 with parent C3#TotalGrades
            C3#Executive at g/l 4/0 with parent C3#TotalGrades
            C3#[None] at g/l 4/0 with parent Channel
            C3#TotalChannels at g/l 4/1 with parent C3#TotalC3
                C3#National_Accts at g/l 4/0 with parent C3#TotalChannels
                C3#Distributor_Sales at g/l 4/0 with parent C3#TotalChannels
                C3#Wireless_Accts at g/l 4/0 with parent C3#TotalChannels
                C3#Retail_Direct at g/l 4/0 with parent C3#TotalChannels
                C3#NoChannel at g/l 4/0 with parent C3#TotalChannels

As you can see, C3#Directory now has C3#TotalChannels underneath, which also makes the outline seem that the children of C3#TotalChannels are also duplicated. This was causing a problem for Dodeca. Note how the generation of C3#Directory is 4, and the C3#TotalChannels appaers to be rightfully set to 5, but then the children have the wrong generation (4) because they just appear as copies of the original members.

The Dodeca HFM connector will now scan the outline/dimensions for these issues and then 'stub' in the member so that this cannot happen, causing the outline to instead present this way:

Channel at g/l 1/5 with parent null
    C3#[None] at g/l 2/0 with parent Channel
    C3#TotalC3 at g/l 2/4 with parent Channel
        C3#TotalChannels at g/l 3/1 with parent C3#TotalC3
            C3#National_Accts at g/l 4/0 with parent C3#TotalChannels
            C3#Distributor_Sales at g/l 4/0 with parent C3#TotalChannels
            C3#Wireless_Accts at g/l 4/0 with parent C3#TotalChannels
            C3#Retail_Direct at g/l 4/0 with parent C3#TotalChannels
            C3#NoChannel at g/l 4/0 with parent C3#TotalChannels
        C3#TotalGrades at g/l 3/3 with parent C3#TotalC3
            C3#Intern at g/l 4/0 with parent C3#TotalGrades
            C3#Junior at g/l 4/0 with parent C3#TotalGrades
            C3#Senior at g/l 4/0 with parent C3#TotalGrades
            C3#Lead at g/l 4/0 with parent C3#TotalGrades
            C3#Manager at g/l 4/0 with parent C3#TotalGrades
            C3#Director at g/l 4/2 with parent C3#TotalGrades
                C3#TotalChannels at g/l 5/0 with parent C3#TotalC3
            C3#VicePresident at g/l 4/0 with parent C3#TotalGrades
            C3#Executive at g/l 4/0 with parent C3#TotalGrades
            C3#[None] at g/l 4/0 with parent Channel
            C3#TotalChannels at g/l 4/0 with parent C3#TotalC3

Note that the two additional C3#TotalChannels now no longer have children and also still appear with correct generation information. We may look at making adjustments to future versions of Dodeca in order to accommodate more flexibility with this, but for now we are treating it somewhat like we would treat a shared member in Essbase.

Version 1.1.7

  • Connector framework now handles the "Disconnect" request from the Dodeca client. This request may be used when stateful connections (Stateless = False) are in use

Version 1.1.6

  • Now contains HFMConnectionTest, a small command-line Java program to see test connectivity to an HFM application (see appendix for usage guide).

Version 1.1.5

  • Fixes to member query commands where HFM hierarchies were appearing flat in a selector tree

  • Enhancements to the way that aliases are handled for members. Aliases can be turned on server-wise in a new application.properties setting, or enabled on a connection-by-connection basis by using the new useAliases parameter on the application in your Essbase connection definition. Note: improvements were specifically made in Dodeca 7.7.2 (and above) to address alias handling. If your version of Dodeca is less than 7.7.2 then you will likely not want to use aliases (in member selector lists) as Dodeca will improperly fetch children, resulting in an error.

  • Servlet now implements Dodeca 'FindAncestors' method that can be called in certain situations when Dodeca wants to expand a dynamic selector tree out to a particular position, such as to highlight the current cached member selection

Version 1.1.4

  • New outline caching strategy of 'none' (configured in application.properties) to disable any caching of outlines. This may be needed/useful if the caching implementation is insufficient due to users having different permissions.

Version 1.1.3

  • Added adjustment to connection code to automatically retry a connection one time. This is a workaround implemented for a customer experiencing issues on the very first connection when the connector is started up

Version 1.1.2

  • You may now have blank rows in your retrieve range. The grid interpreter will assume the entire row within the retrieval area is blank and will not attempt to retrieve data cells for those intersections

  • You may now have blank columns in the retrieve range

  • You may now use 'stacking' with no POV in the retrieve range. For example, the following grid has no POV:

[                    ][              S#Actual][              S#Actual]
[                    ][                Y#2005][                Y#2005]
[                    ][            W#Periodic][            W#Periodic]
[                    ][E#EastRegion.EastSales][E#EastRegion.EastSales]
[                    ][   V#<Entity Currency>][   V#<Entity Currency>]
[                    ][          I#[ICP None]][          I#[ICP None]]
[                    ][      C1#TotalProducts][      C1#TotalProducts]
[                    ][     C2#TotalCustomers][     C2#TotalCustomers]
[                    ][      C3#TotalChannels][      C3#TotalChannels]
[                    ][     C4#ClosingBalance][     C4#ClosingBalance]
[                    ][             P#January][            P#February]
[             A#Sales][             1,322,379][             1,057,903]
  • POV elements may start in any column, except for the first (previously, the starting offset was fixed)

Version 1.1.1

  • New algorithm to build outline with fewer calls to the HFM server. Substantially improves outline build speed.

  • Enhanced metadata on retrieve operations to fill in cell attributes better, such as missing/data. This should allow retrieves to render #Missing and other non-data values better

  • Better error handling (to be more consistent with traditional servlet), show better messages

  • Improved ad hoc grid response metadata: #Missing text now works

Version 1.1.0

  • Completely new framework (sits on embedded Jetty instead of Tomcat). This was done for technical reasons due to the various conflicts between HFM and the frameworks used for this software

  • New tool (jarnivore.jar) ships, runnable jar that helps process and collect the HFM dependency jar files

Version 1.0.5

  • New command-line program that can be used to export an outline XML file. Can be invoked from command-line that is in the Dodeca HFM Connector install folder such as the following: java -cp ./hfmjar/:./lib/ com.appliedolap.dodeca.retroess.hfm.outline.OutlineExporterProgram admin password1 HFMCluster COMMA4DIM There are exactly four parameters: username, password, cluster (server), and application name. A file with the cluster/server and the application name will be generated in the current folder.

  • New fetch member test program

Version 1.0.4

  • Additional logging to try and diagnose issue with outline extraction failing

Version 1.0.3

  • Connector now honors the UseAliases setting and allows you to choose from one of several 'synthetic' alias tables, including: NonUnique, NonUniqueDescription, and NonUniqueAndDescription

Version 1.0.2

  • Fixed issue with the way levels are caculated that was causing a ragged Entity dimension to only show a single member instead of all hierarchies/members

  • Now including generated PDF in distribution

Version 1.0.1

  • Enhance errors to match Dodeca Essbase servlet error style and show more info to client

  • Change default port to 9330

  • Fix issue with StringUtils.join where method may not be present depending on which class is loaded

  • Add servlet context path setting (default is commented out) to application.properties file. Causes ServletPath to need to be adjusted to http://localhost:9330/dodeca-hfm or similar

Version 1.0.0

  • Fix issue when trying to retrieve grid

  • Prevent racing if multiple requests are tying to cache an outline at the same time

Version 0.9.0 (beta)

  • Initial release