External Functions

External Function Example

External functions are functions that can be written on a server that clients can later reference in MDX expressions. External functions can be written by most MDX users. External function names are case sensitive, and unlike internal functions, they are more limited in the arguments that they can take. Here is an example of an MDX query that uses an external function called addOne(), which takes one parameter, a double argument, and adds one (1) to it. It then returns another double argument:
WITH MEMBER measures.x AS
'addone(measures.sales_sum)'
SELECT {cars.members} ON 0 FROM Mddbcars
WHERE (measures.x)
The resulting cells look like this:
0.0[0]: 229001
0.0[1]: 27001
0.0[2]: 40001
0.0[3]: 86001
0.0[4]: 76001
0.0[5]: 17001
0.0[6]: 10001
0.0[7]: 20001
0.0[8]: 20001
0.0[9]: 10001
0.0[10]: 44001
0.0[11]: 17001
0.0[12]: 15001
0.0[13]: 4001
0.0[14]: 14001
0.0[15]: 58001
Here is the query and the resulting cells without the external addOne() function:
SELECT {cars.members} ON 0 
FROM Mddbcars 
WHERE (measures.sales_sum)
Array(0)=229000
Array(1)=27000 
Array(2)=17000 Array(3)=10000 
Array(4)=40000 Array(5)=20000 
Array(6)=20000 Array(7)=86000 
Array(8)=10000 Array(9)=44000 
Array(10)=17000 Array(11)=15000 
Array(12)=76000 Array(13)=4000 
Array(14)=14000 Array(15)=58000

Gaining Access to an External Function Library or Class

Before you can use a function in a query, you must define or open the library for the current session. To do this, you execute the USE statement in MDX:
USE LIBRARY "Hello"
You do not add the .class extension, because it is automatically provided. When the session ends, the library is released. You can use a DROP statement to release the library before the session ends:
DROP LIBRARY "Hello" 

State Information

The class is instantiated when the USE statement is first encountered in a session, and then it is released when the session ends or the DROP statement is executed. As a result, the state can be kept in a normal class and static variables can be maintained. Here is an example:
public
class Hello
{    
   static int count = 0;
   int instance;
   int iteration = 0;
   public Hello()
    { 
      instance = count++;
      System.out.println("Hello constructor " + instance);
    }
    public double addOne(double d)
    {
       System.out.println("addOne, world! " + instance + " " + 
iteration++);
       return d+1.0;
    }
    public void finalize()
    {
       System.out.println("Hello finalize");
    }
 }
Note: System.out is used in the above example for illustration and cannot be used in a real function except for debugging.
Here is an example of the debugging output that is generated:
Hello constructor 0
addOne, world! 0 0
addOne, world! 0 2
Hello constructor 1
addOne, world! 0 3
addOne, world! 1 0
addOne, world! 1 1
        
Each time a new session (a user or client connection) uses this class, the Java constructor is called and a new Hello object is created. The count is incremented so that instance has a unique value. Example items that you might want to save in a real application include file handles, shopping cart lists, and database connection handles.
Although cleanup is automatic, you can have an optional finalize method for special circumstances. Normal Java garbage collection of the class occurs some time after the class is no longer needed. The finalize method should then be called. However, in accordance with Java standards, it is possible that the finalize method will never be called (for example, if the server is shut down early, or the class never needs to be removed by the garbage collector).

Function Arguments and Return Types

Only floating-point (double) arguments and return values are supported by SAS 9.2 OLAP Server. Java function overloading is also supported and there is no limit to the number of arguments that are supported.
SAS OLAP Server looks at the parameters that are passed to an external function and creates a Java signature from that. It then looks up the function and signature in the class. In the addOne() example that was mentioned earlier, there is one parameter. Also, because it is a double argument, it looks for the signature “D(D)”.

Performance

Certain OLAP hosts use an in-process Java virtual machine (JVM), whereas other OLAP hosts use an out-of-process JVM. An out-of-process JVM is much less efficient because each method call has to be packaged (marshaled) and transmitted to the JVM process. It is then unpackaged (unmarshaled) and run, and a return packet is sent back. Currently HP-UX, OpenVMS, and z/OS use out-of-process JVMs. In later releases, hosts should be able to use in-process JVMs. z/OS will use a shared address space so it can be optimized.
Although synthetic benchmarks show that calling Java is considerably slower than calling built-in functions, real-world performance tests show that the performance impact of calling Java methods was negligible (at least with in-process Java implementations). If you encounter a problem, reducing the number of function calls per output cell, the number of cells queried, and the number of parameters to the function can all boost performance.

Deployment

To make a Java class available, copy the .class file to a directory that is listed in the CLASSPATH environment variable when the server is started. The CLASSPATH can contain any number of directories that are separated by semicolons (;). The current release of SAS OLAP Server does not contain a method to make the server reload a .class file after it has been loaded. Therefore, if you update the .class file after using it one time, the server will continue to use the old version. Currently you need either to restart the server or give the new class a different name.
It is possible that later releases of SAS OLAP Server will not use CLASSPATH. A benefit of using Java for external functions is that the .class files are portable. As a result, you can use JavaC to compile your class one time, and deploy it on different machines without recompiling.

Security

Because the Java classes are loaded from the server's local file system, they have full access to the server's system (under the ID that started the server). Any public methods (on any classes) in the CLASSPATH can be invoked by any client. As a result, use caution when you decide which classes and directories to make visible.

Differences with Microsoft Analysis Server (AS2K)