001    /*
002    // $Id: AxisNode.java 245 2009-05-26 21:14:13Z sgwood $
003    // This software is subject to the terms of the Eclipse Public License v1.0
004    // Agreement, available at the following URL:
005    // http://www.eclipse.org/legal/epl-v10.html.
006    // Copyright (C) 2007-2008 Julian Hyde
007    // All Rights Reserved.
008    // You must accept the terms of that agreement to use this software.
009    */
010    package org.olap4j.mdx;
011    
012    import java.io.PrintWriter;
013    import java.util.List;
014    import java.util.Collections;
015    
016    import org.olap4j.Axis;
017    import org.olap4j.type.Type;
018    
019    /**
020     * An axis in an MDX query. For example, the typical MDX query has two axes,
021     * which appear as the "ON COLUMNS" and "ON ROWS" clauses.
022     *
023     * @version $Id: AxisNode.java 245 2009-05-26 21:14:13Z sgwood $
024     */
025    public class AxisNode implements ParseTreeNode {
026    
027        private final ParseRegion region;
028        private boolean nonEmpty;
029        private ParseTreeNode expression;
030        private final Axis axis;
031    
032        private final List<IdentifierNode> dimensionProperties;
033    
034        /**
035         * Creates an axis.
036         *
037         * @param region Region of source code
038         * @param nonEmpty Whether to filter out members of this axis whose cells
039         *    are all empty
040         * @param axis Which axis (ROWS, COLUMNS, etc.)
041         * @param dimensionProperties List of dimension properties; if null,
042         *   empty list is assumed
043         * @param expression Expression to populate the axis
044         */
045        public AxisNode(
046            ParseRegion region,
047            boolean nonEmpty,
048            Axis axis,
049            List<IdentifierNode> dimensionProperties,
050            ParseTreeNode expression)
051        {
052            this.region = region;
053            this.nonEmpty = nonEmpty;
054            this.expression = expression;
055            this.axis = axis;
056            if (axis == null) {
057                throw new IllegalArgumentException("Axis type must not be null");
058            }
059            if (dimensionProperties == null) {
060                dimensionProperties = Collections.emptyList();
061            }
062            this.dimensionProperties = dimensionProperties;
063        }
064    
065        public ParseRegion getRegion() {
066            return region;
067        }
068    
069        public <T> T accept(ParseTreeVisitor<T> visitor) {
070            final T o = visitor.visit(this);
071    
072            // visit the expression which forms the axis
073            expression.accept(visitor);
074    
075            return o;
076        }
077    
078        /**
079         * Returns the name of the axis this axis expression is populating.
080         *
081         * @return axis name
082         */
083        public Axis getAxis() {
084            return axis;
085        }
086    
087        /**
088         * Returns whether the axis has the <code>NON EMPTY</code> property set.
089         *
090         * @return whether the axis is NON EMPTY
091         */
092        public boolean isNonEmpty() {
093            return nonEmpty;
094        }
095    
096        /**
097         * Sets whether the axis has the <code>NON EMPTY</code> property set.
098         *
099         * See {@link #isNonEmpty()}.
100         *
101         * @param nonEmpty whether the axis is NON EMPTY
102         */
103        public void setNonEmpty(boolean nonEmpty) {
104            this.nonEmpty = nonEmpty;
105        }
106    
107        /**
108         * Returns the expression which is used to compute the value of this axis.
109         *
110         * @return the expression which is used to compute the value of this axis
111         */
112        public ParseTreeNode getExpression() {
113            return expression;
114        }
115    
116        /**
117         * Sets the expression which is used to compute the value of this axis.
118         * See {@link #getExpression()}.
119         *
120         * @param expr the expression which is used to compute the value of this
121         * axis
122         */
123        public void setExpression(ParseTreeNode expr) {
124            this.expression = expr;
125        }
126    
127        public void unparse(ParseTreeWriter writer) {
128            PrintWriter pw = writer.getPrintWriter();
129            if (nonEmpty) {
130                pw.print("NON EMPTY ");
131            }
132            if (expression != null) {
133                expression.unparse(writer);
134            }
135            if (dimensionProperties.size() > 0) {
136                pw.print(" DIMENSION PROPERTIES ");
137                for (int i = 0; i < dimensionProperties.size(); i++) {
138                    IdentifierNode dimensionProperty = dimensionProperties.get(i);
139                    if (i > 0) {
140                        pw.print(", ");
141                    }
142                    dimensionProperty.unparse(writer);
143                }
144            }
145            if (axis != Axis.FILTER) {
146                pw.print(" ON " + axis);
147            }
148        }
149    
150        /**
151         * Returns the list of dimension properties of this axis.
152         *
153         * @return list of dimension properties
154         */
155        public List<IdentifierNode> getDimensionProperties() {
156            return dimensionProperties;
157        }
158    
159        public Type getType() {
160            // An axis is not an expression, so does not have a type.
161            // Try AxisNode.getExpression().getType() instead.
162            return null;
163        }
164    
165        public AxisNode deepCopy() {
166            return new AxisNode(
167                this.region,
168                this.nonEmpty,
169                this.axis,
170                MdxUtil.deepCopyList(dimensionProperties),
171                this.expression != null ? this.expression.deepCopy() : null);
172        }
173    }
174    
175    // End AxisNode.java