001/*
002// $Id: CellSetListener.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;
021
022import java.util.List;
023
024/**
025 * Listener interface for receiving events when the contents of a
026 * {@link CellSet} have changed.
027 *
028 * <p>NOTE: This functionality is experimental and is subject to change or
029 * removal without notice.
030 *
031 * <p>The client can ask the server to provide the listener with a specific
032 * {@link Granularity granularity} of events, but the server can decline to
033 * provide that granularity.
034 *
035 * <p>Fine granularity deals with changes such as cell values changing (and
036 * reports the before and after value, before and after formatted value),
037 * positions being deleted, positions being changed.
038 *
039 * <p>When an atomic change happens on the server (say a cache flush, if the
040 * server is mondrian) then an event will arrive on the client containing all of
041 * those changes. Although {@link CellSetChange#getCellChanges} and
042 * {@link CellSetChange#getAxisChanges} return lists, the client should assume
043 * that all of the events in these lists simultaneously.
044 *
045 * <p>At any point, the server is free to throw up its hands and say 'there are
046 * too many changes' by sending null values for {@code getCellChanges} or
047 * {@code getAxisChanges}. This prevents situations where there are huge numbers
048 * of changes that might overwhelm the server, the network link, or the client,
049 * such as might happen if a large axis is re-sorted.
050 *
051 * <p>The client should always be ready for that to happen (even for providers
052 * that claim to provide fine granularity events), and should re-execute the
053 * query to get the cell set. In fact, we recommend that clients re-execute the
054 * query to get a new cellset whenever they get an event. Then the client can
055 * use the details in the event to highlight cells that have changed.
056 *
057 * <h3>Notes for implementors</h3>
058 *
059 * <p>The purpose of registering a listener before creating a cell set is to
060 * ensure that no events "leak out" between creating a cell set and registering
061 * a listener, or while a statement is being re-executed to produce a new cell
062 * set.
063 *
064 * <p>The {@link #cellSetOpened(CellSet)} and {@link #cellSetClosed(CellSet)}
065 * methods are provided so that the listener knows what is going on when a
066 * statement is re-executed. In particular, suppose a statement receives an
067 * change event decides to re-execute. The listener is attached to the
068 * statement, so receives notifications about both old and new cell sets. The
069 * driver implicitls closes the previous cell set and calls
070 * {@code cellSetClosed}, then calls {@code cellSetOpened} with the new cell
071 * set.
072 *
073 * <p>If changes are occurring regularly on the server, there will soon be a
074 * call to {@link #cellSetChanged}. It is important to note that this event
075 * contains only changes that have occurred since the new cell set was opened.
076 *
077 * <p>The granularity parameter is provided to {@link OlapStatement#addListener}
078 * for the server's benefit. If granularity is only {@link Granularity#COARSE},
079 * the server may be able to store less information in order to track the cell
080 * set.
081 *
082 * @version $Id: CellSetListener.java 482 2012-01-05 23:27:27Z jhyde $
083 */
084public interface CellSetListener {
085
086    /**
087     * Invoked when a cell set is opened.
088     *
089     * @param cellSet Cell set
090     */
091    void cellSetOpened(CellSet cellSet);
092
093    /**
094     * Invoked when a cell set is closed.
095     *
096     * @param cellSet Cell set
097     */
098    void cellSetClosed(CellSet cellSet);
099
100    /**
101     * Invoked when a cell set has changed.
102     *
103     * @param cellSetChange Change descriptor
104     */
105    void cellSetChanged(CellSetChange cellSetChange);
106
107    /**
108     * Granularity of notifications that should be sent to a cellset listener.
109     */
110    enum Granularity {
111        FINE,
112        COARSE
113    }
114
115    /**
116     * Description of changes that have occurred to the cell set.
117     */
118    interface CellSetChange {
119        /**
120         * Returns the cell set affected by this change.
121         *
122         * @return Cell set affected by this change.
123         */
124        CellSet getCellSet();
125
126        /**
127         * Returns a list of cells that have changed, or null if the server
128         * cannot provide detailed changes.
129         *
130         * <p>The server is always at liberty to provide a {@code CellSetChange}
131         * without a detailed list of changes, even if
132         * {@link Granularity#COARSE} was specified when the listener was
133         * attached. Here are some typical reasons:<ul>
134         *
135         * <li>If there are very many changes. (Transmitting these changes over
136         * the network would be costly, and the user interface also might
137         * struggle to redisplay so many cells.)
138         *
139         * <li>If the axes have changed significantly. (If an axis position has
140         * changed, all of the cells at that position will necssarily have
141         * changed.)
142         *
143         * <li>If the client did not ask for detailed changes
144         *
145         * <li>If the the provider is not capable of giving detailed changes.
146         * </ul>
147         */
148        List<CellChange> getCellChanges();
149
150        /**
151         * Returns a list of axis changes, or null if server cannot provide
152         * detailed changes.
153         *
154         * <p>The reasons why this method returns null are similar to the
155         * reasons why {@link #getCellChanges()} returns null.
156         *
157         * @return List of changes to positions on axes, or null if the server
158         * cannot provide detailed changes.
159         */
160        List<AxisChange> getAxisChanges();
161    }
162
163    /**
164     * Description of a change to a particular {@link Cell}; part of a
165     * {@link CellSetChange}.
166     */
167    interface CellChange {
168        /**
169         * Returns the cell before the change.
170         */
171        Cell getBeforeCell();
172
173        /**
174         * Returns the cell after the change.
175         */
176        Cell getAfterCell();
177    }
178
179    /**
180     * Description of a change to a particular {@link CellSetAxis}; part of a
181     * {@link CellSetChange}.
182     */
183    interface AxisChange {
184        /**
185         * Returns the axis affected by this change.
186         *
187         * @return Axis affected by this change
188         */
189        CellSetAxis getAxis();
190
191        /**
192         * Returns the position before the change. Null if the change created a
193         * new position.
194         *
195         * @return Position before the change, or null if the position is newly
196         * created
197         */
198        Position getBeforePosition();
199
200        /**
201         * Returns the position after the change. Null if the change deleted
202         * this position.
203         *
204         * @return Position after the change, or null if the position is deleted
205         */
206        Position getAfterPosition();
207    }
208}
209
210// End CellSetListener.java