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:
-
Extract the Dodeca HFM Connector files to the target server
-
Copy reg.properties from your EPM server
-
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
, andNonUniqueDescription
. TheDefaultTopMember
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 newuseAliases
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.3
-
Connector now honors the
UseAliases
setting and allows you to choose from one of several 'synthetic' alias tables, including:NonUnique
,NonUniqueDescription
, andNonUniqueAndDescription
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