/* // This software is subject to the terms of the Eclipse Public License v1.0 // Agreement, available at the following URL: // http://www.eclipse.org/legal/epl-v10.html. // Copyright (C) 2007-2010 Julian Hyde // All Rights Reserved. // You must accept the terms of that agreement to use this software. */ package org.olap4j.driver.olap4ld; import org.olap4j.OlapException; import org.olap4j.driver.olap4ld.Olap4ldCatalog; import org.olap4j.driver.olap4ld.Olap4ldCube; import org.olap4j.driver.olap4ld.Olap4ldDimension; import org.olap4j.driver.olap4ld.Olap4ldHierarchy; import org.olap4j.driver.olap4ld.Olap4ldLevel; import org.olap4j.driver.olap4ld.Olap4ldMember; import org.olap4j.driver.olap4ld.helper.Olap4ldLinkedDataUtil; import org.olap4j.impl.*; import org.olap4j.mdx.ParseTreeNode; import org.olap4j.metadata.*; import org.semanticweb.yars.nx.Literal; import org.semanticweb.yars.nx.Node; import org.semanticweb.yars.nx.Variable; import java.util.*; /** * Implementation of {@link org.olap4j.metadata.Member} * for XML/A providers. * * <p>TODO:<ol> * <li>create members with a pointer to their parent member (not the name)</li> * <li>implement a member cache (by unique name, belongs to cube, soft)</li> * <li>implement Hierarchy.getRootMembers</li> * </ol> * * @author jhyde, bkaempgen * @version $Id: XmlaOlap4jMember.java 372 2010-12-02 20:24:17Z jhyde $ * @since Dec 5, 2007 */ class Olap4ldMember extends Olap4ldElement implements Olap4ldMemberBase, Member, Named { private final Olap4ldLevel olap4jLevel; // TODO: We would rather have a refernce to the parent member, but it is // tricky to populate /* private final XmlaOlap4jMember parentMember; */ private final String parentMemberUniqueName; private final Type type; private Olap4ldMember parentMember; private final int childMemberCount; private final int ordinal; private final Map<Property, Object> propertyValueMap; // Expression directly as ParseTreeNode private final ParseTreeNode expression; /** * Creates an XmlaOlap4jMember. * * @param olap4jLevel Level * @param uniqueName Unique name * @param name Name * @param caption Caption * @param description Description * @param parentMemberUniqueName Unique name of parent, or null if no parent * @param type Type * @param childMemberCount Number of children * @param ordinal Ordinal in its hierarchy * @param propertyValueMap Property values */ Olap4ldMember( Olap4ldLevel olap4jLevel, String uniqueName, String name, String caption, String description, String parentMemberUniqueName, Type type, int childMemberCount, int ordinal, Map<Property, Object> propertyValueMap, ParseTreeNode expression) { super(uniqueName, name, caption, description); this.ordinal = ordinal; assert olap4jLevel != null; assert type != null; this.olap4jLevel = olap4jLevel; this.parentMemberUniqueName = parentMemberUniqueName; this.type = type; this.childMemberCount = childMemberCount; this.propertyValueMap = UnmodifiableArrayMap.of(propertyValueMap); this.expression = expression; } public int hashCode() { return uniqueName.hashCode(); } public boolean equals(Object obj) { return obj instanceof Olap4ldMember && ((Olap4ldMember) obj).uniqueName.equals(uniqueName); } public NamedList<? extends Member> getChildMembers() throws OlapException { final NamedList<Olap4ldMember> list = new NamedListImpl<Olap4ldMember>(); getCube() .getMetadataReader() .lookupMemberRelatives( Olap4jUtil.enumSetOf(TreeOp.CHILDREN), uniqueName, list); return list; } public int getChildMemberCount() { return childMemberCount; } public Olap4ldMember getParentMember() { if (parentMemberUniqueName == null) { return null; } if (parentMember == null) { try { parentMember = getCube().getMetadataReader() .lookupMemberByUniqueName(parentMemberUniqueName); } catch (OlapException e) { throw new RuntimeException("We should find this parent member!"); // FIXME } } return parentMember; } public Olap4ldLevel getLevel() { return olap4jLevel; } public Olap4ldHierarchy getHierarchy() { return olap4jLevel.olap4jHierarchy; } public Olap4ldDimension getDimension() { return olap4jLevel.olap4jHierarchy.olap4jDimension; } public Type getMemberType() { return type; } public boolean isAll() { return type == Type.ALL; } public boolean isChildOrEqualTo(Member member) { throw new UnsupportedOperationException(); } public boolean isCalculated() { return type == Type.FORMULA; } public int getSolveOrder() { throw new UnsupportedOperationException(); } /** * Simply return expression that we have stored with the member. */ public ParseTreeNode getExpression() { return expression; } public List<Member> getAncestorMembers() { final List<Member> list = new ArrayList<Member>(); Olap4ldMember m = getParentMember(); while (m != null) { list.add(m); m = m.getParentMember(); } return list; } public boolean isCalculatedInQuery() { throw new UnsupportedOperationException(); } public Object getPropertyValue(Property property) throws OlapException { return getPropertyValue( property, this, propertyValueMap); } /** * Helper method to retrieve the value of a property from a member. * * @param property Property * @param member Member * @param propertyValueMap Map of property-value pairs * @return Property value * * @throws OlapException if database error occurs while evaluating * CHILDREN_CARDINALITY; no other property throws */ static Object getPropertyValue( Property property, Olap4ldMemberBase member, Map<Property, Object> propertyValueMap) throws OlapException { // If property map contains a value for this property (even if that // value is null), that overrides. final Object value = propertyValueMap.get(property); if (value != null || propertyValueMap.containsKey(property)) { return value; } if (property instanceof Property.StandardMemberProperty) { Property.StandardMemberProperty o = (Property.StandardMemberProperty) property; switch (o) { case MEMBER_CAPTION: return member.getCaption(); case MEMBER_NAME: return member.getName(); case MEMBER_UNIQUE_NAME: return member.getUniqueName(); case CATALOG_NAME: return member.getCatalog().getName(); case CHILDREN_CARDINALITY: return member.getChildMemberCount(); case CUBE_NAME: return member.getCube().getName(); case DEPTH: return member.getDepth(); case DESCRIPTION: return member.getDescription(); case DIMENSION_UNIQUE_NAME: return member.getDimension().getUniqueName(); case DISPLAY_INFO: // TODO: return null; case HIERARCHY_UNIQUE_NAME: return member.getHierarchy().getUniqueName(); case LEVEL_NUMBER: return member.getLevel().getDepth(); case LEVEL_UNIQUE_NAME: return member.getLevel().getUniqueName(); case MEMBER_GUID: // TODO: return null; case MEMBER_ORDINAL: return member.getOrdinal(); case MEMBER_TYPE: return member.getMemberType(); case PARENT_COUNT: return member.getParentMember() == null ? 0 : 1; case PARENT_LEVEL: return member.getParentMember() == null ? 0 : member.getParentMember().getLevel().getDepth(); case PARENT_UNIQUE_NAME: return member.getParentMember() == null ? null : member.getParentMember().getUniqueName(); case SCHEMA_NAME: return member.getCube().olap4jSchema.getName(); case VALUE: // TODO: return null; } } return null; } // convenience method - not part of olap4j API public Olap4ldCube getCube() { return olap4jLevel.olap4jHierarchy.olap4jDimension.olap4jCube; } // convenience method - not part of olap4j API public Olap4ldCatalog getCatalog() { return olap4jLevel.olap4jHierarchy.olap4jDimension.olap4jCube .olap4jSchema.olap4jCatalog; } // convenience method - not part of olap4j API public Olap4ldConnection getConnection() { return olap4jLevel.olap4jHierarchy.olap4jDimension.olap4jCube .olap4jSchema.olap4jCatalog.olap4jDatabaseMetaData .olap4jConnection; } // convenience method - not part of olap4j API public Map<Property, Object> getPropertyValueMap() { return propertyValueMap; } public String getPropertyFormattedValue(Property property) throws OlapException { // FIXME: need to use a format string; but what format string; and how // to format the property on the client side? return String.valueOf(getPropertyValue(property)); } public void setProperty(Property property, Object value) { propertyValueMap.put(property, value); } public NamedList<Property> getProperties() { return olap4jLevel.getProperties(); } public int getOrdinal() { return ordinal; } public boolean isHidden() { throw new UnsupportedOperationException(); } public int getDepth() { // Since in regular hierarchies members have the same depth as their // level, we store depth as a property only where it is different. final Object depth = propertyValueMap.get(Property.StandardMemberProperty.DEPTH); if (depth == null) { return olap4jLevel.getDepth(); } else { return toInteger(depth); } } /** * Converts an object to an integer value. Must not be null. * * @param o Object * @return Integer value */ static int toInteger(Object o) { if (o instanceof Number) { Number number = (Number) o; return number.intValue(); } return Integer.valueOf(o.toString()); } public Member getDataMember() { throw new UnsupportedOperationException(); } public List<Node[]> transformMetadataObject2NxNodes(Cube cube) { List<Node[]> nodes = new ArrayList<Node[]>(); // Create header /* * ?CATALOG_NAME ?SCHEMA_NAME ?CUBE_NAME ?MEASURE_UNIQUE_NAME * ?MEASURE_NAME ?MEASURE_CAPTION ?DATA_TYPE ?MEASURE_IS_VISIBLE * ?MEASURE_AGGREGATOR ?EXPRESSION */ // Create header Node[] header = new Node[] { new Variable("?CATALOG_NAME"), new Variable("?SCHEMA_NAME"), new Variable("?CUBE_NAME"), new Variable("?DIMENSION_UNIQUE_NAME"), new Variable("?HIERARCHY_UNIQUE_NAME"), new Variable("?LEVEL_UNIQUE_NAME"), new Variable("?LEVEL_NUMBER"), new Variable("?MEMBER_NAME"), new Variable("?MEMBER_UNIQUE_NAME"), new Variable("?MEMBER_CAPTION"), new Variable("?MEMBER_TYPE"), new Variable("?PARENT_UNIQUE_NAME"), new Variable("?PARENT_LEVEL") }; nodes.add(header); // See olap4j specification String parentuniquename; String parentlevel; if (this.getParentMember() == null) { parentuniquename = "null"; parentlevel = "null"; } else { parentuniquename = this.getParentMember().getUniqueName(); parentlevel = this.getParentMember().getLevel().getDepth()+""; } Node[] metadatanode = new Node[] { Olap4ldLinkedDataUtil .convertMDXtoURI(cube.getSchema().getCatalog().getName()), Olap4ldLinkedDataUtil .convertMDXtoURI(cube.getSchema().getName()), Olap4ldLinkedDataUtil .convertMDXtoURI(cube.getUniqueName()), Olap4ldLinkedDataUtil .convertMDXtoURI(this.getDimension().getUniqueName()), Olap4ldLinkedDataUtil .convertMDXtoURI(this.getHierarchy().getUniqueName()), Olap4ldLinkedDataUtil .convertMDXtoURI(this.getLevel().getUniqueName()), new Literal(this.getLevel().getDepth()+""), Olap4ldLinkedDataUtil .convertMDXtoURI(this.getName()), Olap4ldLinkedDataUtil .convertMDXtoURI(this.getUniqueName()), new Literal(this.getCaption()), new Literal(this.getMemberType().ordinal()+""), new Literal(parentuniquename), new Literal(parentlevel) }; nodes.add(metadatanode); return nodes; } } // End XmlaOlap4jMember.java