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