//////////////////////////////////////////////////////////////////////////////// // // 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. * *

The member for the implicitly referenced dimension depends on the structure of the dimension: *

*

* * @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 true if the tuple is valid, * and false 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; } } }