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*/
020package org.olap4j.mdx;
021
022import org.olap4j.Axis;
023import org.olap4j.type.Type;
024
025import java.io.PrintWriter;
026import java.util.Collections;
027import 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 */
035public 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