Showing posts with label Essbase java api. Show all posts
Showing posts with label Essbase java api. Show all posts

Wednesday, April 2, 2014

MDX Query Tool - XMLA Edition


Response to the MDX Query Tool has been overwhelmingly positive. My sincere thanks for the emails and comments. They keep me motivated to continue making useful tools. There's nothing quite so discouraging as releasing a tool, only to have no one use it.

Several people, however, experienced the phenomenon of JAR hell, caused by the version of the ess_es_server.jar file in the lib directory. The version here has to exactly match the version of Provider Services running on the server from which you want to retrieve data. I recommended that you find the version on your server and copy it to the MDXQuery/lib folder. This felt like a hack, however, so I started thinking about ways to eliminate this requirement.

Like most Essbase developers, in the back of my mind I knew that Essbase supported XMLA, but had never really thought about using it - until now. The main appeal at first was that no Essbase-specific jars are needed. However, as the Wikipedia article on XMLA states, "XML for Analysis (abbreviated as XMLA) is an industry standard for data access in analytical systems, such as OLAP and data mining." It's used by other vendors (Microsoft, Pentaho, SAS) in other OLAP products besides Essbase (MS Analysis Services, Pentaho/Mondrian - open-source, Jedox - open-source). I don't have any of these products installed, but theoretically at least, you could point this version of the MDX Query Tool to them and it should work. Please let me know in the comments if you do this and whether or not it works.

Just as with the original MDX Query Tool, you can download the MDX Query Tool - XMLA Edition from my Google drive, no Google account needed. After unzipping, there are two files to launch: MDXQueryXMLA.bat (for Windows) and MDXQueryXMLA.sh (for the superior operating systems). As a zip file cannot maintain file permissions, you'll need to 'chmod a+x MDXQueryXMLA.sh' on *NIX and Mac OS X. This tool has been incorporated into cubeSavvy Utilities with improved functionality. You can download it here.

After launching the MDXQueryXMLA.bat|sh file, you'll need to input the appropriate parameters for your environment, as seen below. The sharp-eyed will notice that there are no longer fields to enter Application and Cube information. This is not necessary through XMLA, since the MDX expression already contains this information in the FROM statement. For this reason alone I like it better than the Essbase Java API version that uses IEssOpMdxQuery.

As before, clicking on the "Save to file" button at the bottom will open a dialog box that will allow you to choose a file path/name for the file. You can then open this file, copy the contents, and paste directly to Excel.

Happy MDX querying!


Sunday, March 16, 2014

MDX Query Tool

I really like MDX. Its syntax and power make it an invaluable tool in any Essbase professional's tool-kit. However, Hyperion/Oracle has not made a very user-friendly way to output MDX queries. You can use MaxL to output the results, but then you have to parse all the extraneous bits to make the result useful. You can use EAS to view the results of your MDX query, but there's no way to copy the data table to use somewhere else.

Therefore, I put together a GUI utility that uses the Essbase Java API to output the result of an MDX query to a table that can then be saved to a file. The file is tab-delimited, so it can easily be imported to Excel. The tool is ever so aptly named the MDX Query Tool. Hey, I'm an Essbase geek, not a marketing guru! If anyone else has a better name, I'm willing to rebrand the tool posthaste.

You can download the MDX Query Tool from my Google drive, no Google account needed. As you can see, there are two files to launch: MDXQuery.bat (for Windows) and MDXQuery.sh (for the superior operating systems). As a zip file cannot maintain file permissions, you'll need to 'chmod a+x MDXQuery.sh' on *NIX and Mac OS X. Please use cubeSavvy Utilities, which has improved functionality for displaying MDX properties. You can download it here.

Once unzipped, you'll see a lib directory. The ess_es_server.jar file included with the MDX Query Tool is for version 11.1.2.3. If you're on a different version, you'll need to find the ess_es_server.jar in your install and copy it to the lib directory. For example, it resides in ORACLE_HOME/common/EssbaseJavaAPI/11.1.2.0/lib in my 11.1.2.3 installation.

After launching the MDXQuery.bat|sh file, you'll need to input the appropriate parameters for your environment, as seen below:
Clicking on the "Save to file" button at the bottom will open a dialog box that will allow you to choose a file path/name for the file. You can then open this file, copy the contents, and paste directly to Excel. If there is demand, I will add the ability to copy the results directly from the table to the clipboard. Just let me know in the comments.

I hope this tool makes it easier for you to work with MDX queries.

Sunday, February 9, 2014

Essbase runtime subvars in 11.1.2.3


The Oracle blog has a good explanation of the new runtime subvars functionality available starting in 11.1.2.3. At the end of that post they vaguely hint that it's possible to access this feature from the APIs. So I did a little research into adding the ability to pass runtime subvars from a grid in cubeSavvyLite to a calc script.

First, let's start with a simple calc script in Sample.Basic (named calcSubs):
SET UPDATECALC off;
SET RUNTIMESUBVARS { 
Currmonth = "Jun";
Currlocation = "Florida";
Currproduct="100";
};

FIX(&Currmonth, &Currlocation)
&Currproduct;
ENDFIX
I'd like to point out here that the new runtimesubvars command is very finicky. "SET RUNTIMESUBVARS" (in all capital letters, as above) works, but "SET runtimesubvars" will not even validate.

The Scala code (cubeSavvyLite is written in Scala, not Java) to call the "calcSubs" calc script and pass in the runtime subvars is:
val ess: IEssbase = IEssbase.Home.create(IEssbase.JAPI_VERSION)
val dom: IEssDomain = ess.signOn("admin", "password", false, null, "http://apsServer:portNumber/aps/JAPI")
val olapSvr: IEssOlapServer = dom.getOlapServer("serverName")
olapSvr.connect()
val cube: IEssCube = olapSvr.getApplication("Sample").getCube("Basic")
cube.calcFileWithRunTimeSubVars(
     false, "calcSubs", "Currmonth=\"Feb\";Currlocation=\"Texas\";Currproduct=\"200\";"
)
olapSvr.disconnect()
Looking at the Sample.Basic log, we see the following entry:
Calculating [ Product(200)] with fixed members [Year(Feb); Market(Texas)]

Runtime subvars will be coming soon to cubeSavvyLite. And they will allow you to pass in Page, Row, and Column members from the grid. The grid, in turn, is created from your report script definition.

I'm also looking at making the runtime subvars available in pre-11.1.2.3 versions, as they're really just simple find-and-replaces in the calc script. Please let me know if that's something you'd be interested in having available.

Friday, February 15, 2013

new MaxL "export outline" XML to delimited text parser - orders of magnitude faster

The Java code in my last post works fine for XML containing less than 70,000 members, which is usually sufficient for BSO cubes. ASO cubes, however, can contain a LOT more members. Dan Pressman contacted me earlier in the week to let me know that his XML dimension export file containing 4 million members in almost 90 million lines of XML was taking over 17 hours to run (when it wasn't crashing from running out of memory).

So I rewrote the code to make it more efficient. The same XML above with 90 million lines now takes about 3.5 minutes to run and only uses 75MB of RAM. The functionality is even improved, in that member attributes are now also output. A header line is also prepended, which, due to Java I/O, adds about a minute to the process.

I recommend using this new code for all files instead of the code in the previous post. You can find the two files needed in my GitHub essbase-parse-export-outline-xml-to-text repository.

I also created a very simple Java GUI that allows you to choose the input file, output file, and delimiter:

You can use the XMLOutlineParser.jar file from the above GitHub repository to launch the GUI. If you have a fairly recent Java jre or jdk installed (version 6 or higher), you should be able to save the jar file to your local drive, then double-click on it to launch the GUI.

P.S. As you can see in the comments, some people have experienced issues when trying to save the output file on Windows. The following steps are the workaround to this permissions issue:
  1. Go to Start -> Programs -> Accessories
  2. right click on Command Prompt and select "Run as administrator"
  3. cd to the directory where you saved essbase-parse-export-outline-xml-to-text
  4. run "java -jar XMLOutlineParser.jar"
You can avoid this issue entirely by not selecting an output location at the root of the C directory (e.g. C:\test). Rather use one such as "C:\Documents and Settings\harry\outputFile.txt".

Update: I've added the ability to pass in command line arguments, making XMLOutlineParser suitable for scripting in batch and shell scripts. Passing in arguments will prevent the GUI from running. 
  • run java -jar XMLOutlineParser.jar "input file: path & name" "output file: path & name" "field separator to use in output file"
  • -------e.g. java -jar XMLOutlineParser.jar "/Users/harry/year.xml" "/Users/harry/Documents/year.txt" "!"

Wednesday, January 30, 2013

Parse MaxL export outline xml to flat file - see next post for updated, faster code

The new (as of 11.1.2) MaxL "export outline" command has made using the Essbase Java API to export outlines obsolete. It is an order of magnitude faster and doesn't run into the typical Essbase japi issue with ports. The only problem is that it exports to XML format. The resulting file is more difficult to use in downstream processes than a delimited text file. It also can't be used to import back into Essbase. Luckily, however, it is a fairly simple matter to parse the XML to a flat file with a delimiter of your choice:
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileWriter;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.Reader;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;

import org.w3c.dom.Attr;
import org.w3c.dom.Document;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.ErrorHandler;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import org.xml.sax.SAXParseException;

/***
 * 
 * @author Harry Gates

Usage
 * 1) Use the MaxL "export outline" command to export a dimension of the outline
 *   export outline "/path_to_otl/Sample.otl" list dimensions {"Account"} with alias_table "Default" to xml_file "/path_to_save_xml/sample_account_dim.xml";
 * 2) Change the delimiter, inputFile, and outputFile
 * 3) Compile and run MaxLExportOutlineParseXML.java
 */

public class MaxLExportOutlineParseXML implements ErrorHandler {
 public static String delimiter;
 public static String inputFile;
 public static String outputFile;
 
 public static void main(String[] args) {
  delimiter = "?";
  inputFile = "/path_to_save_xml/sample_account_dim.xml";
  outputFile = "/path_to_save_result/sample_account_dim.txt";
  
  try {
   convertXML();
  } catch (Exception e) {
   e.printStackTrace();
  }
 }
 
  public static void convertXML() throws Exception {
    String output = "";
   
    DocumentBuilderFactory builderFactory = DocumentBuilderFactory.newInstance();
    builderFactory.setNamespaceAware(false);
    builderFactory.setValidating(false);
    builderFactory.setIgnoringElementContentWhitespace(true);
    DocumentBuilder builder = null;
    
    File file = new File(inputFile);
       
    InputStream inputStream= new FileInputStream(file);
    Reader reader = new InputStreamReader(inputStream);
     
    InputSource is = new InputSource(reader);
    is.setEncoding("UTF-8");
    
    builder = builderFactory.newDocumentBuilder();
    builder.setErrorHandler(new MaxLExportOutlineParseXML());
    Document xmlDoc = builder.parse(is);
    
    NodeList mbrNL = xmlDoc.getElementsByTagName("Member");
    
    NodeList dimNL = xmlDoc.getElementsByTagName("Dimension");
    String dimName = dimNL.item(0).getAttributes().getNamedItem("name").getNodeValue().replaceAll("\\r\\n|\\r|\\n", " ");
     
    String header = "PARENT0," + dimName + delimiter + "CHILD0," + dimName + delimiter + "ALIAS0," + dimName
     + delimiter + "PROPERTY0," + dimName + delimiter + "FORMULA0," + dimName + delimiter;
    int udaCountTotal = 0;
      
    BufferedWriter outputStream;
    outputStream = new BufferedWriter(new FileWriter(outputFile));
    
    if (mbrNL.getLength() > 0) {
        Node node = null;
  
  for (int i = 0; i < mbrNL.getLength(); i++) {
      node = mbrNL.item(i);
   
      if (node.hasChildNodes()) {
       String memberName = "";
       String parentName = "";
       String UDA = "";
       String alias = "";
       String dataStorage = "";
       String timeBalance = "";
       String memberFormula = "";
       String twoPassCalc = "";
       String consolidation = "";
       String varianceReporting = "";
       int udaCount = 0;
       
       NodeList list = node.getChildNodes();
       for (int j = 0; j < list.getLength(); j++) {
         if (list.item(j).getNodeName().equals("UDA")) {
          UDA += list.item(j).getTextContent().replaceAll("\\r\\n|\\r|\\n", " ") + delimiter;
          udaCount++;
         }
         if (list.item(j).getNodeName().equals("Alias")) {
          alias = list.item(j).getTextContent().replaceAll("\\r\\n|\\r|\\n", " ").replaceAll("\"", " ");
         }      
       }
       udaCountTotal = udaCount > udaCountTotal ? udaCount : udaCountTotal;
    
    NamedNodeMap nodAttrs = node.getAttributes();
       for (int k = 0; k < nodAttrs.getLength(); k++) {
           Attr nodAttr = (Attr)nodAttrs.item(k);
           String nodName = nodAttr.getNodeName();
           if (nodName.equals("name")) {
             parentName = node.getParentNode().getAttributes().getNamedItem("name").getNodeValue().replaceAll("\\r\\n|\\r|\\n", " ");
             memberName = node.getAttributes().getNamedItem("name").getNodeValue().replaceAll("\\r\\n|\\r|\\n", " ");
             parentName = parentName.replaceAll("\"", " ");
             memberName = memberName.replaceAll("\"", " ");
           } else if (nodName.equals("Consolidation")) {
            consolidation = nodAttr.getNodeValue().replaceAll("\"", " ");
            consolidation = consolidation.trim();
           } else if (nodName.equals("DataStorage")) {
            dataStorage = nodAttr.getNodeValue().replaceAll("\"", " ");
            if (dataStorage.equals("DynamicCalc")) {
             dataStorage = "X";
            } else if (dataStorage.equals("DynamicCalcAndStore")) {
             dataStorage = "V";
            } else if (dataStorage.equals("LabelOnly")) {
             dataStorage = "O";
            } else if (dataStorage.equals("NeverShare")){
             dataStorage = "N";
            } else if (dataStorage.equals("ShareData")){
             dataStorage = "";
            }
            dataStorage = dataStorage.trim();
           } else if (nodName.equals("MemberFormula")) {
            memberFormula = nodAttr.getNodeValue();
           } else if (nodName.equals("TwoPassCalc")) {
            twoPassCalc = nodAttr.getNodeValue().replaceAll("\"", " ");
            twoPassCalc = twoPassCalc.equals("Y") ? "T" : twoPassCalc;
            twoPassCalc = twoPassCalc.trim();
           } else if (nodName.equals("TimeBalance")) {
            timeBalance = nodAttr.getNodeValue().replaceAll("\"", " ");
            if (timeBalance.equals("Last")) {
             timeBalance = "L";
            } else if (timeBalance.equals("First")) {
             timeBalance = "F";
            } else if (timeBalance.equals("Average")) {
             timeBalance = "A";
            }
            timeBalance = timeBalance.trim();
           } else if (nodName.equals("VarianceReporting")) {
            varianceReporting = nodAttr.getNodeValue().replaceAll("\"", " ");
            varianceReporting = varianceReporting.equals("Expense") ? "E" : varianceReporting;
            varianceReporting = varianceReporting.trim();
           } else {
            System.out.println(nodAttr.getNodeName() + ": " + nodAttr.getNodeValue());
           }
       }
       
       consolidation = consolidation.equals("") ? "+" : consolidation;
       consolidation = consolidation.equals("") ? "" : " " + consolidation;
       timeBalance = timeBalance.equals("") ? "" : " " + timeBalance;
       dataStorage = dataStorage.equals("") ? "" : " " + dataStorage;
       twoPassCalc = twoPassCalc.equals("") ? "" : " " + twoPassCalc;
       varianceReporting = varianceReporting.equals("") ? "" : " " + varianceReporting;
       
       String properties = consolidation + timeBalance + dataStorage + twoPassCalc + varianceReporting;
          
       output += parentName.replaceAll(" +", " ").trim()
         + delimiter + memberName.replaceAll(" +", " ").trim()
         + delimiter + alias.replaceAll(" +", " ").trim()
         + delimiter + properties.trim()
         + delimiter + memberFormula
         + delimiter + UDA.replaceAll(" +", " ").trim() + "\n";
      }
      }
    }
    System.out.println("udaCountTotal: " + udaCountTotal);
    String udaHeader = "";
    for (int i = 0; i < udaCountTotal; i++) {
     udaHeader += "UDA0," + dimName + delimiter;
    }
    header += udaHeader;
    output = header + "\n" + output;
    outputStream.append(output);
    outputStream.close();
  }
  
  public void fatalError(SAXParseException spe) throws SAXException {
    System.out.println("Fatal error at line " + spe.getLineNumber());
    System.out.println(spe.getMessage());
    throw spe;
  }

  public void warning(SAXParseException spe) {
    System.out.println("Warning at line " + spe.getLineNumber());
    System.out.println(spe.getMessage());
  }

  public void error(SAXParseException spe) {
    System.out.println("Error at line " + spe.getLineNumber());
    System.out.println(spe.getMessage());
  }
}

Saturday, October 2, 2010

Essbase outline extraction using the Java API

We all wonder why Hyperion/Oracle have never provided a built-in utility to allow extraction of metadata from an Essbase outline. The AppliedOLAP extractor is great, as long as you're on Windows. If you're on Linux or UNIX, your only 2 choices are 1) use the AppliedOLAP outline extractor from a Windows client machine or 2) write your own extractor using the Essbase Java API. The first choice is not really viable if you want to automate the extraction process. In a production environment do you really want to have the process running from a separate Windows machine? Windows is not very reliable on its good days...

This post is about the second option - using the Essbase japi to write an outline extractor. The ViewOutlineTree.java file in the Samples folder provides a great start, but it only outputs the member names in a tree format. What about the member properties, like UDAs, aliases, etc.? Fortunately, it is very easy to add these properties to the output. Take a look at the modified ViewOutlineTree.java code below to give you an idea.


/*
    File: ViewOutlineTree.java 1.0, 2010-6-24

    Copyright (c) Harry Gates

 */



import java.io.BufferedWriter;
import java.io.FileWriter;
import java.io.IOException;

import com.essbase.api.base.*;
import com.essbase.api.session.*;
import com.essbase.api.datasource.*;
import com.essbase.api.domain.*;
import com.essbase.api.metadata.*;

/**
    A platform-independent Essbase outline extractor.

    @author Harry Gates
    @version 1.0, 24 Jun 10
 */

public class ViewOutlineTree {

    // NOTE: The following variables will be set from the runViewOutlineTree.sh script on the Essbase server.

    private static String s_userName;
    private static String s_password; // = "password";
    private static String s_olapSvrName; // = "localhost";
    private static String s_provider = "http://servername:13080/aps/JAPI"; // = "embedded"; // Default
    private static String s_application = "Sample"; // = "IhtGl_X";
    private static String s_database = "Basic"; // = "Main";
    private static String s_dimension = "Product";
    private static String s_delimiter = "?"; // = ",";
    private static String s_file; // = "test.txt";
    static long stoptime = 2000L; //2 Seconds
    private static IEssCube cube = null;
    private static IEssOlapServer olapSvr = null;
    private static IEssCubeOutline otl = null;
    private static IEssIterator associatedAttributes;
    private static BufferedWriter outputStream;
    private static int iAssociatedAttributes_count;
    private static int iUDA_count;
    private static final int FAILURE_CODE = 1;

    public static void main(String[] args) {
        int statusCode = 0;
        IEssbase ess = null;
        long startTime = System.currentTimeMillis();
  
        try {
//            acceptArgs(args);
            // Create JAPI instance.
            ess = IEssbase.Home.create(IEssbase.JAPI_VERSION);

            // Sign On to the Provider
            IEssDomain dom = ess.signOn(s_userName, s_password, false, null, s_provider);

            // Open connection with olap server and get the cube.
            olapSvr = (IEssOlapServer)dom.getOlapServer(s_olapSvrName);
            olapSvr.connect();
            cube = olapSvr.getApplication(s_application).getCube(s_database);
       
            // get the outline members for the specified dimension
            //  builds the s_output string containing all members
            listOutlineMembers(cube);
         
         // close the outline
            otl.close();
            otl = null;
         
            // add the header to the s_output string containing the list of outline members
            writeFileHeader();
        } catch (EssException x) {
            System.err.println("Error: " + x.getMessage());
            statusCode = FAILURE_CODE;
        } catch (InterruptedException e) {
   e.printStackTrace();
  } catch (IOException e) {
   e.printStackTrace();
  } finally {
            try {
                if (olapSvr != null && olapSvr.isConnected() == true)
                    olapSvr.disconnect();
            } catch (EssException x) {
                System.err.println("Error: " + x.getMessage());
            }

            try {
                if (ess != null && ess.isSignedOn() == true)
                    ess.signOff();
            } catch (EssException x) {
                System.err.println("Error: " + x.getMessage());
            }
          
            long elapsedTimeMillis = System.currentTimeMillis()-startTime;
            float elapsedTimeMin = elapsedTimeMillis/(60*1000F);
            System.out.println("minutes to run: " + elapsedTimeMin);
            // Set status to failure only if exception occurs and do abnormal termination
            // otherwise, it will by default terminate normally
            if (statusCode == FAILURE_CODE) System.exit(FAILURE_CODE);
        }
    }

    static void listOutlineMembers(IEssCube cube) throws EssException, InterruptedException, IOException {
        otl = null;
        try {
            otl = cube.openOutline();
        
            IEssIterator dims = otl.getDimensions();
            for (int i = 0; i < dims.getCount(); i++) {
                IEssDimension dim = (IEssDimension)dims.getAt(i);
           
                if (s_dimension.equals(dim.getName())) {
                 outputStream = new BufferedWriter(new FileWriter(s_file + "/" + dim.getName() + ".txt"));
                 associatedAttributes = dim.getDimensionRootMember().getAssociatedAttributes();
                 iAssociatedAttributes_count = associatedAttributes.getCount();
                
                    // run the recursive method to walk the outline tree
                 listOutlineMembers_helper(dim.getDimensionRootMember());
               
                 outputStream.close();
                }
            }         
        } catch (EssException x) {
            System.err.println("Error: " + x.getMessage());
            if (otl != null) {
                try {
                    otl.close();
                } catch (EssException e) {
                    System.err.println("Error: " + e.getMessage());
                }
            }
        }
    }
 
    static void listOutlineMembers_helper(IEssMember mbr) throws EssException, InterruptedException, IOException {
     
        IEssIterator mbrs = mbr.getChildMembers(false);
        for (int i = 0; i < mbrs.getCount(); i++) {
         IEssMember mb = (IEssMember)mbrs.getAt(i);
         displayMemberProperties(mb);
            listOutlineMembers_helper(mb);
        }
    }
   
    private static void displayMemberProperties(IEssMember mbr) throws EssException, IOException {
     String s_output = "";
     IEssMemberSelection mbrSel = null;
   
     s_output += mbr.getParent().getName() + s_delimiter + mbr.getName() + s_delimiter;

//      Member alias
        String s_alias = mbr.getAlias("default");
        s_alias = s_alias == null ? "" : s_alias;
        s_output +=  s_alias + s_delimiter;
         
        String s_consType = mbr.getConsolidationType().toString();
        s_output += s_consType.replaceAll(" .*$", "") + s_delimiter;
     
//      Formulas: not needed for Organisation dimension
        String frm = mbr.getFormula();
        if (frm != null) {
         s_output = s_output + frm.replaceAll("\\r?\\n", " ") + s_delimiter;
        }
      
        s_output += s_delimiter;      

//      UDAs
        String[] s_UDAs = mbr.getUDAs();
        if (s_UDAs != null) {
         for (int i = 0; i < s_UDAs.length; i++) {
          s_output = s_output + s_UDAs[i] + s_delimiter;
         }

         if (s_UDAs.length < iUDA_count) s_output += repeat(s_delimiter, iUDA_count - s_UDAs.length);
         iUDA_count = s_UDAs.length > iUDA_count ? s_UDAs.length : iUDA_count;
        } else {
         s_output += repeat(s_delimiter, iUDA_count);
        }
    
        write2File(s_output, true);
    }

    private static String repeat(String src, int repeat) {
     StringBuffer buf=new StringBuffer();
     for (int i=0; i<repeat; i++) {
      buf.append(src);
     }
     return buf.toString();
    }
      
    private static void write2File(String msg, boolean bNewLine) throws IOException {
  outputStream.write(msg);
  if (bNewLine) outputStream.newLine();
    }
  
    private static void writeFileHeader() throws EssException, IOException {
     String s_header  = "PARENT0,Time" + s_delimiter + "CHILD0,Time" + s_delimiter + "ALIAS0,Time" + s_delimiter + "PROPERTY0,Time" + s_delimiter + "FORMULA0,Time" + s_delimiter;
     String sNewHeader = s_header.replaceAll("Time", s_dimension);
     outputStream = new BufferedWriter(new FileWriter(s_file + "/" + s_dimension + "_header.txt"));
   
     outputStream.write(sNewHeader);

//  add UDAs to header
  for (int j = 0; j < iUDA_count; j++) {
   outputStream.write("UDA0," + s_dimension + s_delimiter);
  }
 
  outputStream.close();
    }

    static void acceptArgs(String[] args) throws EssException {
        if (args.length >= 7) {
            s_userName = args[0];
            s_password = args[1];
            s_olapSvrName = args[2];
            s_provider = args[3];
            s_application = args[4];
            s_database = args[5];
            s_dimension = args[6];
            s_delimiter = args[7];
            s_file = args[8];
        }
    }
}