blob: 56ed822943ccf003d07dc60a4ee00a0249220c98 [file] [log] [blame]
////////////////////////////////////////////////////////////////////////////////
//
// Licensed to the Apache Software Foundation (ASF) under one or more
// contributor license agreements. See the NOTICE file distributed with
// this work for additional information regarding copyright ownership.
// The ASF licenses this file to You under the Apache License, Version 2.0
// (the "License"); you may not use this file except in compliance with
// the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
////////////////////////////////////////////////////////////////////////////////
package mx.olap
{
import flash.utils.Dictionary;
import mx.collections.ArrayCollection;
import mx.collections.IList;
import mx.core.mx_internal;
use namespace mx_internal;
/**
* The OLAPTuple class reprsents a tuple expression pointing to an OLAP cube cell.
* A tuple is made up of one member from every dimension that is contained within a cube.
* The complete expression of a tuple identifier is made up of one or more explicitly specified members,
* in parentheses.
* A tuple can be fully qualified, can contain implicit members, or can contain a single member.
* Any dimension that is not explicitly referenced within a tuple is implicitly referenced.
*
* <p>The member for the implicitly referenced dimension depends on the structure of the dimension:
* <ul>
* <li>If the implicitly referenced dimension has a default member,
* the default member is added to the tuple.</li>
* <li>If the implicitly referenced dimension has no default member,
* the (All) member of the default hierarchy is used.</li>
* <li>If the implicitly referenced dimension has no default member,
* and the default hierarchy has no (All) member,
* the first member of the topmost level of the default hierarchy is used.</li>
* </ul>
* </p>
*
* @see mx.olap.IOLAPTuple
*
* @langversion 3.0
* @playerversion Flash 9
* @playerversion AIR 1.1
* @productversion Flex 3
*/
public class OLAPTuple implements IOLAPTuple
{
include "../core/Version.as";
//--------------------------------------------------------------------------
//
// Constructor
//
//--------------------------------------------------------------------------
/**
* Constructor
*
* @langversion 3.0
* @playerversion Flash 9
* @playerversion AIR 1.1
* @productversion Flex 3
*/
public function OLAPTuple()
{
super();
}
//--------------------------------------------------------------------------
//
// Variables
//
//--------------------------------------------------------------------------
/**
* @private
* For improving performance we cache the computed members list here.
* We need to clear this cache when user alters the tuple by adding
* a new element.
*/
private var cachedMembers:ArrayCollection = new ArrayCollection();
/**
* @private
* Flag which indicates the validity of the cachedMembers variable.
* If the flag is false we need to rebuild the cachedMemebers.
*/
private var cacheValid:Boolean;
//a copy of members added by the user
private var _explicitMembers:ArrayCollection = new ArrayCollection();
/**
* @private
* Flag which indicates the validity of the _explicityMembers variable.
* If the flag is false we need to rebuild the _explicityMembers.
*/
private var explicitMembersValid:Boolean = false;
//original lists of members added by user
private var _userMembers:Array = [];
//--------------------------------------------------------------------------
//
// Properties
//
//--------------------------------------------------------------------------
//----------------------------------
// explicitMembers
//----------------------------------
/**
* @inheritDoc
*
* @langversion 3.0
* @playerversion Flash 9
* @playerversion AIR 1.1
* @productversion Flex 3
*/
public function get explicitMembers():IList
{
if (!explicitMembersValid)
{
_explicitMembers.source = _userMembers.slice(0);
explicitMembersValid = true;
}
return _explicitMembers;
}
//----------------------------------
// userMembers
//----------------------------------
/**
* @private
*/
mx_internal function get userMembers():Array
{
var temp:Array = [];
for each (var m:IOLAPMember in _userMembers)
{
temp.push(m);
// member should not be from the attribute hierarchy because
// in that case there won't be any parent other than all.
if (!(m.hierarchy is OLAPAttribute))
{
m = m.parent;
while (m && OLAPHierarchy(m.hierarchy).allLevel != m.level)
{
temp.push(m);
m = m.parent;
}
}
}
return temp;
}
//----------------------------------
// members
//----------------------------------
/**
* @private
* A list of IOLAPMember instances that represent the members of the tuple.
*/
mx_internal function get members():IList
{
if (cacheValid)
return cachedMembers;
var temp:Array = [];
// get the cube and all its dimensions
var cube:OLAPCube = (_userMembers[0] as IOLAPMember).level.hierarchy.dimension.cube as OLAPCube;
//get all levels in all dimensions
var attributeLevels:Array = cube.attributeLevels;
// get all user specified levels
var userLevels:Dictionary = new Dictionary();
for each (var m:IOLAPMember in _userMembers)
{
// if the member has parent we need to include it too
// example: if 2000-Q1-Jan is added by the user we need to
// add Q1 and 2000
//if (userLevels[m.level] != undefined && userLevels[m.level] != m)
// trace("*** Over writing a level specification ***");
userLevels[m.level] = m;
var mt:IOLAPMember = m;
//skip the all level?
while (mt.parent && mt.parent.parent)
{
mt = mt.parent;
//if (userLevels[mt.level] != undefined && userLevels[m.level] != m)
// trace("*** Over writing a level specification ***");
userLevels[mt.level] = mt;
}
}
//check which levels user has covered, add the remaining levels all member.
var n:int = attributeLevels.length;
for (var i:int = 0; i < n; ++i)
{
// has user covered this level?
var level:OLAPAttributeLevel = attributeLevels[i];
var hierarchy:OLAPHierarchy = level.hierarchy as OLAPHierarchy;
var newMem:IOLAPMember = userLevels[level];
if (!newMem)
{
// see if user is using the level from the user defined hierarchy
if (hierarchy is OLAPAttribute)
newMem = userLevels[level.userLevel];
}
if (newMem)
{
temp.push(newMem);
if (level == hierarchy.allLevel)
++i;
}
else
{
if (level == hierarchy.allLevel)
{
if (!userLevels[attributeLevels[i + 1]] &&
!userLevels[attributeLevels[i + 1].userLevel])
{
temp.push(hierarchy.allMember);
++i;
}
}
else
{
if (level.levelAllMember)
temp.push(level.levelAllMember);
else
temp.push(hierarchy.defaultMember);
}
}
}
//search for user specified measure
var measureFound:Boolean = false;
for each (var measure:Object in explicitMembers)
{
if (measure is OLAPMeasure)
{
measureFound = true;
temp.push(measure);
break;
}
}
//if no measure was found take the default one
if (!measureFound)
temp.push(cube.defaultMeasure);
cachedMembers.source = temp;
cacheValid = true;
return cachedMembers;
}
//----------------------------------
// membersArray
//----------------------------------
/**
* Intead of accessing members this is used to access
* the internal array to avoid creating a duplicate.
*
* @langversion 3.0
* @playerversion Flash 9
* @playerversion AIR 1.1
* @productversion Flex 3
*/
mx_internal function get membersArray():Array
{
var x:IList = members;
return cachedMembers.source;
}
//----------------------------------
// isValid
//----------------------------------
/**
* @private
* Contains <code>true</code> if the tuple is valid,
* and <code>false</code> if not.
*/
mx_internal function get isValid():Boolean
{
//check if we have any member from attribute hierarchy and the same member from
// a user defined hierarchy-level. If it is present then this is a invalid tuple (for now!)
var n:int = _userMembers.length;
for (var i:int = 0; i < n; ++i)
{
var member:OLAPMember = _userMembers[i];
var attrHierarchy:OLAPAttribute = member.hierarchy as OLAPAttribute;
if (!attrHierarchy)
continue;
var memLevel:OLAPLevel = attrHierarchy.userHierarchyLevel;
for (var j:int = 0; j < n; ++j)
{
if (j == i)
continue;
var nextMember:OLAPMember = _userMembers[j];
if (nextMember.level == memLevel)
return false;
}
}
var cube:OLAPCube = (_userMembers[0] as IOLAPMember).dimension.cube as OLAPCube;
return cube.isTupleValid(this);
}
//--------------------------------------------------------------------------
//
// Methods
//
//--------------------------------------------------------------------------
/**
* @inheritDoc
*
* @langversion 3.0
* @playerversion Flash 9
* @playerversion AIR 1.1
* @productversion Flex 3
*/
public function addMembers(value:IList):void
{
explicitMembersValid = false;
cacheValid = false;
var n:int = value.length;
for (var i:int = 0; i < n; ++i)
{
_userMembers.push(value.getItemAt(i));
}
}
/**
* @private
* Removes members from the tuple.
*
* @param element The members to remove, as a list of IOLAPMember instances.
*/
mx_internal function removeElements(value:IList):void
{
explicitMembersValid = false;
cacheValid = false;
var n:int = value.length;
for (var i:int = 0; i < n; ++i)
{
var removeIndex:int = _userMembers.indexOf(value.getItemAt(i));
if (removeIndex != -1)
_userMembers.splice(removeIndex, 1);
}
}
/**
* @private
* Removes members from the tuple.
*
* @param element The members to remove, as a list of IOLAPMember instances.
*/
mx_internal function removeElementsAtEnd(count:int):void
{
explicitMembersValid = false;
cacheValid = false;
_userMembers.splice(-1, count);
}
/**
* @inheritDoc
*
* @langversion 3.0
* @playerversion Flash 9
* @playerversion AIR 1.1
* @productversion Flex 3
*/
public function addMember(element:IOLAPElement):void
{
explicitMembersValid = false;
cacheValid = false;
if (element is IOLAPDimension)
{
var dim:IOLAPDimension = element as IOLAPDimension;
OLAPTrace.traceMsg("Getting default member of dimension:" + dim.name,
OLAPTrace.TRACE_LEVEL_3);
_userMembers.push(dim.defaultMember);
}
else if (element is IOLAPHierarchy)
{
var h:IOLAPHierarchy = element as IOLAPHierarchy;
_userMembers.push(h.defaultMember);
OLAPTrace.traceMsg("Getting default member of hierarchy:" + h.name,
OLAPTrace.TRACE_LEVEL_3);
}
else if (element is IOLAPMember)
{
_userMembers.push(element);
}
else if (element is IOLAPLevel)
{
// should we just pick up the first member?
OLAPTrace.traceMsg("Error a level is being passed as input to tuple:" + element.name,
OLAPTrace.TRACE_LEVEL_1);
}
}
/**
* Removes all members from the tuple.
*
* @langversion 3.0
* @playerversion Flash 9
* @playerversion AIR 1.1
* @productversion Flex 3
*/
mx_internal function clear():void
{
cacheValid = false;
_userMembers.splice(0);
explicitMembersValid = false;
}
/**
* Creates a clone of this tuple.
*
* @langversion 3.0
* @playerversion Flash 9
* @playerversion AIR 1.1
* @productversion Flex 3
*/
mx_internal function clone():OLAPTuple
{
var newTuple:OLAPTuple = new OLAPTuple;
newTuple._userMembers = _userMembers.slice(0);
return newTuple;
}
}
}