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 */
020 package org.olap4j;
021
022 import 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 */
084 public 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