For the complete code for most of the examples in this chapter, see the example programs available from the Overview of the Oracle OLAP Java API Reference.

6.1 Overview of Source Objects

After you have used the classes in the oracle.olapi.metadata.mdm package to get MdmSource objects that represent measures and dimensions in the OLAP Catalog, you can get Source objects from them. You can also create other Source objects with methods of a DataProvider. You can then use the Source objects to create a query to get dimension or measure values from the database. To retrieve data from the database, you use a Source to create a Cursor.

With the methods of a Source, you can specify selections of dimension or measure values and specify operations on the elements of the Source, such as mathematical calculations, comparisons, and ordering, adding or removing elements of a query. The Source class has a few primary methods and many shortcut methods that use one or more of the primary methods. The most complex primary methods are the join(Source joined, Source comparison, int comparisonRule, boolean visible) method and the recursiveJoin(Source joined, Source comparison, Source parent, int comparisonRule, boolean parentsFirst, boolean parentsRestrictedToBase, int maxIterations, boolean visible) method. The many other signatures of the join and recursiveJoin methods are shortcuts for certain operations of the primary methods.

In this chapter, the information about the join method applies equally to the recursiveJoin method, except where otherwise noted. With the join method, you can select elements of a Source and, most importantly, you can relate the elements of one Source to those of another Source. For example, to specify the dimension elements that a measure requires, you use a join method to relate the dimension to the measure.

A Source has certain characteristics, such as a type and a data type, and it sometimes has one or more inputs or outputs. This chapter describes these concepts. It also describes the different kinds of Source objects and how you get them, the join method and other Source methods, and how you use those methods to specify a query.

6.2 Kinds of Source Objects

The kinds of Source objects that you use to specify data and to perform analysis, and the ways that you get them, are the following:

Primary Source objects, which are returned by the getSource method of an MdmSource object such as an MdmDimension or an MdmMeasure. A primary Source provides access to the data that the MdmSource represents. Getting primary Source objects is usually the first step in creating a query. You then typically select elements from the primary Source objects, thus producing derived Source objects in the process.

Derived Source objects, which you get by calling methods on a Source object. Methods such as join return a new Source that is based on the Source on which you call the method. All queries on the data store, other than a simple list of values specified by the primary Source for an MdmSubdimension, such as an MdmLevelHierarchy or an MdmLevel, are derived Source objects.

Fundamental Source objects, which are returned by the getSource method of a FundamentalMetadataObject. These Source objects represent the OLAP API data types.

List or range Source objects that you get by calling the createConstantSource, createListSource or createRangeSource methods of a DataProvider. Typically, you use this kind of Source as the joined or comparison parameter to the join method.

Dynamic Source objects, which are returned by the getSource method of a DynamicDefinition. A dynamic Source is usually a derived Source. It is generated by a Template, which you use to create a dynamic query that you can revise after interacting with an end user.

Parameterized Source objects, which are returned by the createParameterizedSource methods of a DataProvider. Like a list or range Source, you use a parameterized Source as a parameter to the join method. Unlike a list or range Source, however, you can change the value that the Parameter represents after the join operation and thereby change the selection that the derived Source represents. You can create a Cursor for that derived Source and retrieve the results of the query. You can then change the value of the Parameter, and, without having to create a new Cursor for the derived Source, use that same Cursor to retrieve the results of the modified query.

The Source class has the following subclasses:

BooleanSource

DateSource

NumberSource

StringSource

These subclasses have different data types and implement Source methods that require those data types. Each subclass also implements methods unique to it, such as the implies method of a BooleanSource or the indexOf method of a StringSource.

6.3 Characteristics of Source Objects

A Source has a data type and a type, a Source identification (ID), and a SourceDefinition. This topic describes these concepts. Some Source objects have one or more inputs or outputs. Those complex concepts are discussed in the "Inputs and Outputs of a Source" topic.

6.3.1 Data Type of a Source

As described in Chapter 2, " Understanding OLAP API Metadata", the OLAP API has a class, FundamentalMetadataObject, that represents the data type of the elements of an MdmSource. The data type of a Source is represented by a fundamental Source. For example, a BooleanSource has elements that have Java boolean values. The data type of a BooleanSource is the fundamental Source that represents OLAP API Boolean values.

To get the fundamental Source that represents the data type of a Source, call the getDataType method of the Source. You can also get a fundamental Source by calling the getSource method of a FundamentalMetadataObject.

Example 6-1 demonstrates getting the fundamental Source for the OLAP API String data type, the Source for the data type of an MdmPrimaryDimension, and the Source for the data type of the Source for the MdmPrimaryDimension, and comparing them to verify that they are all the same object. In the example, dp is the DataProvider and mdmProdDim is the MdmPrimaryDimension for the PRODUCT dimension.

6.3.2 Type of a Source

Along with a data type, a Source has a type, which is the Source from which the elements of the Source are drawn. The type of a Source determines whether the join method can match the Source to an input of another Source. The only Source that does not have a type is the fundamental Source for the OLAP API Value data type, which represents the set of all values, and from which all other Source objects ultimately descend.

The type of a fundamental Source is its data type. The type of a list or range Source is the data type of the values of the elements of the list or range Source.

The type of a primary Source is one of the following:

The fundamental Source that represents the data type of the values of the elements of the primary Source. For example, the Source returned by getSource method of a typical MdmMeasure is the fundamental Source that represents the set of all OLAP API number values.

The Source for the MdmSource of which the MdmSource of the primary Source is a component. For example, the type of the Source returned by the getSource method of an MdmLevelHierarchy is the Source for the MdmPrimaryDimension of which the hierarchy is a component.

The type of a derived Source is one of the following:

Its baseSource, which is the Source whose method returned the derived Source. A Source returned by the alias, extract, join, recursiveJoin, or value methods, or one of their shortcuts, has its base Source as its type. An exception is the derived Source returned by the distinct method, whose type is the type of its base Source rather than the base Source itself.

A fundamental Source. Methods such as position and count return a Source that has the fundamental Source for the OLAP API Integer data type as its type. Methods that make comparisons, such as eq, le, and so on, return a Source that has the fundamental Source for the Boolean data type as its type. Methods that perform aggregate functions, such as the NumberSource methods total and average, return as the type of the Source a fundamental Source that represents the function.

You can find the type of a Source by calling its getType method.

A Source derived from another Source is a subtype of the Source from which it is derived. You can use the isSubtypeOf method to determine if a Source is a subtype of another Source.

For example, in Example 6-2 the myList object is a list Source. The example uses myList to select values from prodRollup, a Source for the default MdmLevelHierarchy of the MdmPrimaryDimension for the PRODUCT dimension. In the example, dp is the DataProvider. Because prodSel is a subtype of prodRollup, the condition in the if statement is true.

The type of both myList and prodRollup is the fundamental String Source. The type of prodSel is prodRollup because the elements of prodSel are derived from the elements of prodRollup.

The supertype of a Source is the type of the type of a Source, and so on, up through the types to the Source for the fundamental Value data type. For example, the fundamental Value Source is the type of the fundamental String Source, which is the type of prodRollup, which is the type of prodSel. The fundamental Value Source and the fundamental String Source are both supertypes of prodSel. The prodSelSource is a subtype of prodRollup, and of the fundamental String Source, and of the fundamental Value Source.

6.3.3 Source Identification and SourceDefinition of a Source

A Source has an identification, an ID, which is a String that uniquely identifies it during the current connection to the database. You can get the identification of a Source by calling its getID method. For example, the following code gets the identification of the Source for the MdmPrimaryDimension for the PRODUCT dimension and displays the value.

System.out.println("The Source ID of prodDim is " +
prodDim.getID());

The preceding code displays the following:

The Source ID of prodDim is Hidden..D_GLOBAL.PRODUCT

The text displayed by Example 6-9 has several examples of source identifications.

Each Source has a SourceDefinition object, which records information about the Source. The different kinds of Source objects have different kinds of SourceDefinition objects. For example, the fundamental Source for an MdmPrimaryDimension has an MdmSourceDefinition, which is a subclass of HiddenDefinition, which is a subclass of SourceDefinition.

The SourceDefinition of a Source that is produced by a call to the join method is an instance of the JoinDefinition class. From a JoinDefinition you can get information about the parameters of the join operation that produced its Source, such as the base Source, the joined Source, the comparison Source, the comparison rule, and the value of the visible parameter.

6.4 Inputs and Outputs of a Source

The inputs and the outputs of a Source are complex and powerful aspects of the class. This section describes the concepts of inputs and outputs and provides examples of how they are related.

6.4.1 Inputs of a Source

An input of a Source is also a Source. An input indicates that the values of the Source with the input depend upon an unspecified set of values of the input. A Source that matches to the input provides the values that the input requires. You match an input to a Source by using the join method. For information on how to match a Source to an input, see "Matching a Source To an Input".

Certain Source objects always have one or more inputs. They are the Source objects for MdmDimensionedObject subclasses MdmMeasure and MdmAttribute. They have inputs because the values of the measure or attribute are specified by the values of their dimensions. The inputs of the Source for the measure or attribute are the Source objects for the dimensions of the measure or the attribute. Before you can retrieve the data for a measure or an attribute, you must match each input to a Source that provides the required values.

Some Source methods produce a Source that has an input. You can produce a Source that has an input by using the extract, position, or value methods. These methods provide a means of producing a Source whose elements are a subset of the elements of another Source. A Source produced by one of these methods has its base Source as an input.

For example, in the following code, the base Source is prodRollup. Its value method produces prodRollupValues, which has prodRollup as an input.

Source prodRollupValues = prodRollup.value();

The input provides the means to select values from prodRollup, as demonstrated by Example 6-2. The selectValues method in Example 6-2 is a shortcut for the following join method.

The parameters of the join method specify the elements of the base Source that appear in the resulting Source. In the example, the joined parameter is the Source produced by the prodRollup.value() method. The resulting unnamed Source has prodRollup as an input. The input is matched by the base of the join method, which is also prodRollup. The result of the join operation, prodSel, has the values of prodRollup that match the values of prodRollup that are in the comparison Source, myList.

If the joined Source were prodRollup and not the Source produced by prodRollup.value(), then the comparison would be between the Source object itself and the values of the comparison Source and not between the values of the Source and the values of the comparison Source. Because the joined Source object does not match any of the values of the comparison Source, the result of the join method would have all of the elements of prodRollup instead of having only the values of prodRollup that are specified by the values of the joined Source that match the values of the comparison Source as specified by the comparison rule.

The input of a Source produced by the position or value method, and an input intrinsic to an MdmDimensionedObject, are regular inputs. A regular input causes the join method, when it matches a Source to the input, to compare the values of the comparison Source to the values of the Source that has the input rather than to the input Source itself.

The input of a Source produced by the extract method is an extraction input. An extraction input differs from a regular input in that, when a value of the Source that has the extraction input is a Source, the join method extracts the values of the Source that is a value of the Source that has the input. The join method then compares the values of the comparison Source to the extracted values rather than to the Source itself.

A Source can have from zero to many inputs. You can get all of the inputs of a Source by calling its getInputs method, the regular inputs by calling its getRegularInputs method, and its extraction inputs by calling its getExtractionInputs method. Each of those methods returns a Set of Source objects.

6.4.2 Outputs of a Source

The join method returns a Source that has the elements of its base Source that are specified by the parameters of the method. If the value of the visible parameter is true, then the joined Source becomes an output of the returned Source. An output of a Source returned by the join method has the elements of the joined Source that specify the elements of the returned Source. An output is a means of identifying the elements of the joined Source that specify the elements of the Source that has the output.

A Source can have from zero to many outputs. You can get the outputs of a Source by calling its getOutputs method, which returns a List of Source objects.

A Source with more than one output has one or more elements for each set of the elements of the outputs. For example, a Source that represents a measure that has had all of its inputs matched, and has had the Source objects that match the inputs turned into outputs, has a single type element for each set of the elements of its outputs because each data value of the measure is identified by a unique set of the values of its dimensions. A Source that represents dimension values that are selected by some operation performed on the data of a measure, however, might have more than one element for each set of the elements of its outputs. An example is a Source that represents product values that have unit costs greater than a certain amount. Such a Source might have several products for each time period that have a unit cost greater than the specified amount.

Example 6-3 produces a selection of the elements of shipRollup, which is a Source for a hierarchy of a dimension of customer values. The customers are grouped by a shipment origination and destination hierarchy.

Example 6-3 Using the join Method To Produce a Source Without an Output

The shipRollupValuesSource has an input of shipRollup. In the join method in the example, the base Source, shipRollup, matches the input of the joined Source, shipRollupValues because the base and the input are the same object. The join method selects the elements of the base shipRollup whose values match the values of the joined shipRollup that are specified by the comparison Source, custValuesToSelect. The method produces a Source, custSel, that has only the selected elements of shipRollup. Because the visible parameter is false, the joined Source is not an output of custSel. The custSelSource therefore has only two elements, the values of which are SHIPMENTS_ROLLUP::REGION::9 and SHIPMENTS_ROLLUP::REGION::10.

You produce a Source that has an output by specifying true as the visible parameter to the join method. Example 6-4 joins the Source objects for the dimension selections from Example 6-2 and Example 6-3 to produce a Source, custSelByProdSel, that has one output. The custSelByProdSelSource has the elements from custSel that are specified by the elements of prodSel.

The comparison Source is an empty Source, which has no elements and which is the result of the getEmptySource method of the DataProvider, dp. The comparison rule value, COMPARISON_RULE_REMOVE, selects only the elements of prodSel that are not in the comparison Source. Because the comparison Source has no elements, all of the elements of the joined Source are selected. Each of the elements of the joined Source specify all of the elements of the base Source. The resulting Source, custSelByProdSel, therefore has all of the elements of custSel.

Because the visible parameter is true in Example 6-4, prodSel is an output of custSelByProdSel. Therefore, for each element of the output, custSelByProdSel has the elements of custSel that are specified by that element of the output. Because the custSel and prodSel are both simple lists of dimension values, the result is the cross product of the elements of both Source objects.

To actually retrieve the data specified by custSelByProdSel, you must create a Cursor for it. Such a Cursor contains the values shown in the following table, which has headings added that indicate that the values from the output, prodSel, are in the left column and the values from the elements of the custSelByProdSelSource, which are derived from its type, custSel, are in the right column.

The custSelByProdSelSource has two type elements, and its output has four elements. The number of elements of custSelByProdSel is eight because for this Source, each output element specifies the same set of two type elements.

Each join operation that specifies a visible parameter of true adds an output to the list of outputs of the resulting Source. For example, if a Source has two outputs and you call one of its join methods that produces an output, then the Source that results from the join operation has three outputs. You can get the outputs of a Source by calling its getOutputs method, which returns a List of Source objects.

Example 6-5 demonstrates joining a measure to selections from the dimensions of the measure, thus matching to the inputs of the measure Source objects that provide the required elements. Because the last two join methods match the dimension selections to the inputs of the measure, the resulting Source does not have any inputs. Because the visible parameter in those joins is true, the last join method produces a Source that has two outputs.

Example 6-5 gets the Source for the measure of unit costs. That Source, unitCost, has two inputs, which are the primary Source objects for the TIME and PRODUCT dimensions, which are the dimensions of unit cost. The example gets the Source objects for level hierarchies of the dimensions, which are subtypes of the Source objects for the dimensions. It produces selections of the level hierarchies and then joins those selections to the measure. The result, unitCostSel, specifies the unit costs of the selected products at the selected times.

The unnamed Source that results from joining timeSel to unitCost has one output, which is timeSel. Joining prodSel to that unnamed Source produces unitCostSel, which has two outputs, timeSel and prodSel. The unitCostSelSource has the elements from its type, unitCost, that are specified by its outputs.

A Cursor for unitCostSel contains the following, displayed as a table with headings added that indicate the structure of the Cursor. A Cursor has the same structure as its Source. The unit cost values are formatted as dollar values.

Output 1 has the values from prodSel, output 2 has the values from timeSel, and the type values are the values from unitCost that are specified by the output values.

Because these join operations are performed by most OLAP API applications, the API provides shortcuts for these and many other join operations. Example 6-6 uses shortcuts for the join operations in Example 6-5 to produce the same result.

6.4.3 Matching a Source To an Input

In a join operation, a Source-to-input match occurs only between the base Source and the joined Source. A Source matches an input if one of the following conditions is true.

The Source is the same object as the input or it is a subtype of the input.

The Source has an output that is the same object as the input or the output is a subtype of the input.

The output has an output that is the same object as the input or is a subtype of the input.

The join operation looks for the conditions in the order in the preceding list. It searches the list of outputs of the Source recursively, looking for a match to the input. The search ends with the first matching Source. An input can match with only one Source, and two inputs cannot match with the same Source.

When a Source matches an input, the result of the join method has the elements of the base that match the elements specified by the parameters of the method. You can determine if a Source matches another Source, or an output of the other Source, by passing the Source to the findMatchFor method of the other Source.

When a Source matches an input, the resulting Source does not have that input. Matching a Source to an input does not affect the outputs of the base Source or the joined Source. If a base Source has an output that matches the input of the joined Source, the resulting Source does not have the input but it does have the output.

If the base Source or the joined Source in a join operation has an input that is not matched in the operation, then the unmatched input is an input of the resulting Source.

The comparison Source of a join method does not participate in the input matching. If the comparison Source has an input, then that input is not matched and the Source returned by the join method has that same input.

Example 6-7 demonstrates a base Source matching the input of the joined Source in a join operation. The example uses the position method to produce a Source that has an input, and then uses the join method to match the base of the join operation to the input of the joined Source.

In Example 6-7, the position method returns myListPos, which has the elements of myList and which has myList as an input. The join method matches the base myList to the input of the joined Source, myListPos.

The comparison Source, pos, specifies the positions of the elements of myListPos to match to the positions of the elements of myList. The elements of the resulting Source, myListSel, are the elements of myList whose positions match those specified by the parameters of the join method.

A Cursor for myListSel has the following values.

PRODUCT_ROLLUP::FAMILY::5
PRODUCT_ROLLUP::FAMILY::8

If the visible parameter in Example 6-7 were true instead of false, then the result would have elements from myList and an output of myListPos. A Cursor for myListSel in that case would have the following values, displayed as a table with headings added that indicate the output and type values.

Example 6-8 demonstrates matching outputs of the joined Source to two inputs of the base Source. In the example, units is a Source for an MdmMeasure. It has as inputs the primary Source objects for the TIME, PRODUCT, CUSTOMER, and CHANNEL dimensions.

The DataProvider is dp, and prodRollup, shipRollup, calendar, and chanRollup are the Source objects for the default hierarchies of the PRODUCT, CUSTOMER, TIME, and CHANNEL dimensions, respectively. Those Source objects are subtypes of the Source objects for the dimensions that are the inputs of units.

The join method of prodRollup in the first line of Example 6-8 results in prodSel, which specifies selected product values. In that method, the joined Source is the result of the value method of prodRollup. The joined Source has the same elements as prodRollup, and it has prodRollup as an input. The comparison Source is the list Source that is the result of the createListSource method of the DataProvider.

The base Source of the join method, prodRollup, matches the input of the joined Source. Because prodRollup is the input of the joined Source, the Source returned by the join method has only the elements of the base, prodRollup, that match the elements of the joined Source that appear in the comparison Source. Because the visible parameter value is false, the resulting Source does not have the joined Source as an output. The next three similar join operations in Example 6-8 result in selections for the other three dimensions.

The join method of timeSel has custSel as the joined Source. Its comparison Source is the result of the getEmptySource method, so it has no elements. The comparison rule specifies that the elements of the joined Source that are present in the comparison Source do not appear in the resulting Source. Because the comparison Source has no elements, all of the elements of the joined Source are selected. The true value for the visible parameter causes the joined Source to be an output of the Source returned by the join method. The returned Source, custSelByTime, has the selected elements of the customers dimension and has timeSel as an output.

The join method of prodSel has custSelByTime as the joined Source. It produces prodByCustByTime, which has the selected elements from the PRODUCT dimension and has custSelByTime as an output. Example 6-8 then joins the dimension selections to the unitsSource.

The dimension selections are subtypes of the Source objects that are the inputs of units, and therefore the selections match the inputs of units. The input for the product dimension is matched by prodByCustByTime because prodByCustByTime is a subtype of prodSel, which is a subtype of prodRollup. The input for the customers dimension is matched by the custSelByTime, which is the output of prodByCustByTime.

The custSelByTimeSource is a subtype of custSel, which is a subtype of shipRollup. The input for the times dimension is matched by timeSel, which is the output of custSelByTime. The timeSelSource is a subtype of calendar.

Example 6-8 Matching an Input of the Base Source to an Output of the Joined Source

A Cursor for selectedUnits contains the following values, displayed in a crosstab format with column headings and formatting added. The table has only the local values of the dimension elements. The first two lines are the page edge values of the crosstab, which are the values of the chanSel output of selectedUnits, and the value of timeSel, which is an output of the prodByCustByTime output of selectedUnits. The row edge values of the crosstab are the customer values in the left column, and the column edge values are the products values that head the middle and right columns.

The crosstab has only the local value portion of the unique values of the dimension elements. The measure values are the units sold values specified by the selected dimension values.

To demonstrate turning inputs into outputs, Example 6-9 uses units, which is the Source for the UNITS measure, and defaultHiers, which is an ArrayList of the Source objects for the default hierarchies of the dimensions of the measure. The example gets the inputs and outputs of the Source for the measure. It displays the Source identifications of the Source for the measure and for its inputs. The inputs of the Source for the measure are the Source objects for the MdmPrimaryDimension objects that are the dimensions of the measure.

Example 6-9 next displays the number of inputs and outputs of the Source for the measure. Using the join(Source joined) method, which produces a Source that has the elements of the base of the join operation as its elements and the joined parameter Source as an output, it joins one of the hierarchy Source objects to the Source for the measure, and displays the number of inputs and outputs of the resulting Source. It then joins each remaining hierarchy Source to the result of the previous join operation and displays the number of inputs and outputs of the resulting Source.

Finally the example gets the outputs of the Source produced by the last join operation, and displays the Source identifications of the outputs. The outputs of the last Source are the Source objects for the default hierarchies, which the example joined to the Source for the measure. Because the Source objects for the hierarchies are subtypes of the Source objects for the MdmPrimaryDimension objects that are the inputs of the measure, they match those inputs.

Note that as each successive Source for a hierarchy is joined to the result of the previous join operation, it becomes the first output in the List of outputs of the resulting Source. Therefore, the first output of Join.3 is Hidden..D_GLOBAL.CHANNEL.CHANNEL_ROLLUP, and its last output is Hidden..D_GLOBAL.PRODUCT.PRODUCT_ROLLUP.

6.5 Describing Parameterized Source Objects

Parameterized Source objects provide a way of specifying a query and retrieving different result sets for the query by changing the set of elements specified by the parameterized Source. You create a parameterized Source with a createParameterizedSource method of the DataProvider you are using. In creating the parameterized Source, you supply a Parameter object. The Parameter supplies the value that the parameterized Source specifies.

Parameter objects are similar to CursorInput objects in that you use them to specify an initial value for a Source that is part of a query. A typical use of both Parameter and CursorInput objects is to specify the page edges of a cube. Example 7-9 demonstrates using Parameter objects to specify page edges.

An advantage of Parameter objects over CursorInput objects is that with Parameter objects you can easily fetch from the server only the set of elements that you currently need. Example 7-16 demonstrates using Parameter objects to fetch different sets of elements.

When you create a Parameter object, you supply an initial value for the Parameter. You then create the parameterized Source using the Parameter. You include the parameterized Source in specifying a query. You create a Cursor for the query. You can change the value of the Parameter with its setValue method, which changes the set of elements that the query specifies. Using the same Cursor, you can then display the new set of values.

Example 6-10 demonstrates the use of a Parameter and a parameterized Source to specify an element in a measure dimension. It creates a list Source that has as its element values the Source objects for unit cost and unit price measures. The example creates a StringParameter object that has as its initial value the unique identifying String for the Source for the unit cost measure. That StringParameter is then used to create a parameterized Source.

The example extracts the values from the measures, and then selects the data values that are specified by joining the dimension selections to the measure specified by the parameterized Source. It creates a Cursor for the resulting query and displays the results. After resetting the Cursor position and changing the value of the measParamStringParameter, the example displays the values of the Cursor again.

The dp object is the DataProvider. The context object has a method that displays the values of the Cursor with only the local value of the dimension elements.

The following table displays the first set of values of resultsCursor, with column headings and formatting added. The left column of the table has the local value of the TIME dimension hierarchy. The second column from the left has the short value description of the time value. The third column has the local value of the PRODUCT dimension hierarchy. The fourth column has the short value description of the product value. The fifth column has the UNIT COST measure value for the time and product.