001    /*
002    // $Id: AxisNode.java 482 2012-01-05 23:27:27Z jhyde $
003    //
004    // Licensed to Julian Hyde under one or more contributor license
005    // agreements. See the NOTICE file distributed with this work for
006    // additional information regarding copyright ownership.
007    //
008    // Julian Hyde licenses this file to you under the Apache License,
009    // Version 2.0 (the "License"); you may not use this file except in
010    // compliance with the License. You may obtain a copy of the License at:
011    //
012    // http://www.apache.org/licenses/LICENSE-2.0
013    //
014    // Unless required by applicable law or agreed to in writing, software
015    // distributed under the License is distributed on an "AS IS" BASIS,
016    // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
017    // See the License for the specific language governing permissions and
018    // limitations under the License.
019    */
020    package org.olap4j.mdx;
021    
022    import org.olap4j.Axis;
023    import org.olap4j.type.Type;
024    
025    import java.io.PrintWriter;
026    import java.util.Collections;
027    import java.util.List;
028    
029    /**
030     * An axis in an MDX query. For example, the typical MDX query has two axes,
031     * which appear as the "ON COLUMNS" and "ON ROWS" clauses.
032     *
033     * @version $Id: AxisNode.java 482 2012-01-05 23:27:27Z jhyde $
034     */
035    public class AxisNode implements ParseTreeNode {
036    
037        private final ParseRegion region;
038        private boolean nonEmpty;
039        private ParseTreeNode expression;
040        private final Axis axis;
041    
042        private final List<IdentifierNode> dimensionProperties;
043    
044        /**
045         * Creates an axis.
046         *
047         * @param region Region of source code
048         * @param nonEmpty Whether to filter out members of this axis whose cells
049         *    are all empty
050         * @param axis Which axis (ROWS, COLUMNS, etc.)
051         * @param dimensionProperties List of dimension properties; if null,
052         *   empty list is assumed
053         * @param expression Expression to populate the axis
054         */
055        public AxisNode(
056            ParseRegion region,
057            boolean nonEmpty,
058            Axis axis,
059            List<IdentifierNode> dimensionProperties,
060            ParseTreeNode expression)
061        {
062            this.region = region;
063            this.nonEmpty = nonEmpty;
064            this.expression = expression;
065            this.axis = axis;
066            if (axis == null) {
067                throw new IllegalArgumentException("Axis type must not be null");
068            }
069            if (dimensionProperties == null) {
070                dimensionProperties = Collections.emptyList();
071            }
072            this.dimensionProperties = dimensionProperties;
073        }
074    
075        public ParseRegion getRegion() {
076            return region;
077        }
078    
079        public <T> T accept(ParseTreeVisitor<T> visitor) {
080            final T o = visitor.visit(this);
081    
082            // visit the expression which forms the axis
083            expression.accept(visitor);
084    
085            return o;
086        }
087    
088        /**
089         * Returns the name of the axis this axis expression is populating.
090         *
091         * @return axis name
092         */
093        public Axis getAxis() {
094            return axis;
095        }
096    
097        /**
098         * Returns whether the axis has the <code>NON EMPTY</code> property set.
099         *
100         * @return whether the axis is NON EMPTY
101         */
102        public boolean isNonEmpty() {
103            return nonEmpty;
104        }
105    
106        /**
107         * Sets whether the axis has the <code>NON EMPTY</code> property set.
108         *
109         * See {@link #isNonEmpty()}.
110         *
111         * @param nonEmpty whether the axis is NON EMPTY
112         */
113        public void setNonEmpty(boolean nonEmpty) {
114            this.nonEmpty = nonEmpty;
115        }
116    
117        /**
118         * Returns the expression which is used to compute the value of this axis.
119         *
120         * @return the expression which is used to compute the value of this axis
121         */
122        public ParseTreeNode getExpression() {
123            return expression;
124        }
125    
126        /**
127         * Sets the expression which is used to compute the value of this axis.
128         * See {@link #getExpression()}.
129         *
130         * @param expr the expression which is used to compute the value of this
131         * axis
132         */
133        public void setExpression(ParseTreeNode expr) {
134            this.expression = expr;
135        }
136    
137        public void unparse(ParseTreeWriter writer) {
138            PrintWriter pw = writer.getPrintWriter();
139            if (nonEmpty) {
140                pw.print("NON EMPTY ");
141            }
142            if (expression != null) {
143                expression.unparse(writer);
144            }
145            if (dimensionProperties.size() > 0) {
146                pw.print(" DIMENSION PROPERTIES ");
147                for (int i = 0; i < dimensionProperties.size(); i++) {
148                    IdentifierNode dimensionProperty = dimensionProperties.get(i);
149                    if (i > 0) {
150                        pw.print(", ");
151                    }
152                    dimensionProperty.unparse(writer);
153                }
154            }
155            if (axis != Axis.FILTER) {
156                pw.print(" ON " + axis);
157            }
158        }
159    
160        /**
161         * Returns the list of dimension properties of this axis.
162         *
163         * @return list of dimension properties
164         */
165        public List<IdentifierNode> getDimensionProperties() {
166            return dimensionProperties;
167        }
168    
169        public Type getType() {
170            // An axis is not an expression, so does not have a type.
171            // Try AxisNode.getExpression().getType() instead.
172            return null;
173        }
174    
175        public AxisNode deepCopy() {
176            return new AxisNode(
177                this.region,
178                this.nonEmpty,
179                this.axis,
180                MdxUtil.deepCopyList(dimensionProperties),
181                this.expression != null ? this.expression.deepCopy() : null);
182        }
183    }
184    
185    // End AxisNode.java