1111 */
1212package com .dxfeed .model ;
1313
14- import java .util .*;
15- import java .util .concurrent .Executor ;
16-
17- import com .dxfeed .api .*;
18- import com .dxfeed .event .*;
14+ import com .dxfeed .api .DXEndpoint ;
15+ import com .dxfeed .api .DXFeed ;
16+ import com .dxfeed .api .DXFeedEventListener ;
17+ import com .dxfeed .api .DXFeedSubscription ;
18+ import com .dxfeed .event .IndexedEvent ;
19+ import com .dxfeed .event .IndexedEventSource ;
20+ import com .dxfeed .event .TimeSeriesEvent ;
1921import com .dxfeed .impl .AbstractIndexedList ;
2022
23+ import java .util .ArrayList ;
24+ import java .util .Arrays ;
25+ import java .util .List ;
26+ import java .util .ListIterator ;
27+ import java .util .NoSuchElementException ;
28+ import java .util .Objects ;
29+ import java .util .concurrent .Executor ;
30+
2131/**
22- * Abstract model for a list of indexed events.
32+ * <p> Abstract model for a list of indexed events.
2333 * This class handles all snapshot and transaction logic of {@link IndexedEvent} class and
2434 * arranges incoming events into a list ordered by their {@link IndexedEvent#getSource() source} {@link IndexedEventSource#id() id}
2535 * and {@link IndexedEvent#getIndex() index}. Note, that {@link TimeSeriesEvent} extends {@link IndexedEvent} in
5060 * {@link DXFeedSubscription} class.
5161 *
5262 * <h3>Resource management and closed models</h3>
53- *
63+ * <p>
5464 * Attached model is a potential memory leak. If the pointer to attached model is lost, then there is no way to detach
5565 * this model from the feed and the model will not be reclaimed by the garbage collector as long as the corresponding
5666 * feed is still used. Detached model can be reclaimed by the garbage collector, but detaching model requires knowing
6272 *
6373 * <h3><a name="threadsAndLocksSection">Threads and locks</a></h3>
6474 *
65- * This class is <b>not</b> tread-safe and requires external synchronization.
75+ * <p> This class is <b>not</b> tread-safe and requires external synchronization.
6676 * The only thread-safe methods are {@link #attach attach}, {@link #detach detach} and {@link #close close}.
6777 *
6878 * <p> You must query the state of {@link #attach(DXFeed) attached} model only from
@@ -107,7 +117,7 @@ public abstract class AbstractIndexedEventModel<E extends IndexedEvent<?>, N ext
107117
108118 // An element for each source, typically just one or very few, ordered by sourceId
109119 @ SuppressWarnings ("unchecked" )
110- private Source [] sources = (Source [])new AbstractIndexedEventModel .Source [1 ];
120+ private Source [] sources = (Source []) new AbstractIndexedEventModel .Source [1 ];
111121 private int nSources ;
112122
113123 private Object symbol ;
@@ -132,7 +142,7 @@ protected AbstractIndexedEventModel(Class<? extends E> eventType) {
132142 * Creates new model attached to the specified feed. It is not subscribed to any symbol.
133143 * Use {@link #setSymbol} to specify subscription symbol.
134144 *
135- * @param feed feed to attach to.
145+ * @param feed feed to attach to.
136146 * @param eventType the event type.
137147 * @throws NullPointerException if event type is null.
138148 */
@@ -176,6 +186,7 @@ public void close() {
176186 /**
177187 * Returns executor for processing event notifications on this model.
178188 * See <a href="#threadsAndLocksSection">Threads and locks</a> section of this class documentation.
189+ *
179190 * @return executor for processing event notifications on this model,
180191 * or {@code null} if default executor of the attached {@link DXFeed} is used.
181192 */
@@ -186,8 +197,9 @@ public Executor getExecutor() {
186197 /**
187198 * Changes executor for processing event notifications on this model.
188199 * See <a href="#threadsAndLocksSection">Threads and locks</a> section of this class documentation.
200+ *
189201 * @param executor executor for processing event notifications on this model,
190- * or {@code null} if default executor of the attached {@link DXFeed} is used.
202+ * or {@code null} if default executor of the attached {@link DXFeed} is used.
191203 */
192204 public void setExecutor (Executor executor ) {
193205 subscription .setExecutor (executor );
@@ -204,6 +216,7 @@ public void clear() {
204216 /**
205217 * Returns model subscription symbol, or {@code null} is not subscribed
206218 * (this is a default value).
219+ *
207220 * @return model subscription symbol.
208221 */
209222 public Object getSymbol () {
@@ -213,26 +226,30 @@ public Object getSymbol() {
213226
214227 /**
215228 * Changes symbol for this model to subscribe for.
229+ *
216230 * @param symbol model subscription symbol, use {@code null} to unsubscribe.
217231 */
218232 public void setSymbol (Object symbol ) {
219233 if (Objects .equals (this .symbol , symbol ))
220234 return ;
221235 if (this .symbol != null ) {
222- for (int i = 0 ; i < nSources ; i ++)
236+ for (int i = 0 ; i < nSources ; i ++) {
223237 sources [i ].clearImpl ();
238+ }
224239 notifyChanged (true );
225240 }
226241 this .symbol = symbol ;
227- if (symbol != null )
242+ if (symbol != null ) {
228243 subscription .setSymbols (symbol );
229- else
244+ } else {
230245 subscription .clear ();
246+ }
231247 }
232248
233249 /**
234250 * Returns size limit of this model.
235251 * It is equal to {@link Integer#MAX_VALUE} by default (no limit).
252+ *
236253 * @return size limit of this model.
237254 */
238255 public int getSizeLimit () {
@@ -242,6 +259,7 @@ public int getSizeLimit() {
242259 /**
243260 * Changes size limit of this model. When size limit is exceed, the
244261 * first entries from this model are dropped.
262+ *
245263 * @param sizeLimit size limit of this model.
246264 * @throws IllegalArgumentException if {@code sizeLimit} is negative.
247265 */
@@ -257,18 +275,21 @@ public void setSizeLimit(int sizeLimit) {
257275 /**
258276 * Returns the number of elements in this model.
259277 * It is limited by {@link #getSizeLimit() sizeLimit} property.
278+ *
260279 * @return the number of elements in this model.
261280 */
262281 protected int size () {
263282 // It is O(nSources) now. todo: make it O(log(nSources))
264283 int size = 0 ;
265- for (int i = 0 ; i < nSources ; i ++)
284+ for (int i = 0 ; i < nSources ; i ++) {
266285 size += sources [i ].size ();
286+ }
267287 return size ;
268288 }
269289
270290 /**
271291 * Returns the element at the specified position in this model.
292+ *
272293 * @param index index of the element to return.
273294 * @return the element at the specified position in this model.
274295 * @throws IndexOutOfBoundsException if the index is out of range
@@ -291,16 +312,18 @@ protected E get(int index) {
291312
292313 /**
293314 * Returns a list iterator over the elements in this model (in proper sequence).
315+ *
294316 * @return a list iterator over the elements in this model (in proper sequence).
295317 */
296318 @ SuppressWarnings ("unchecked" )
297319 protected ListIterator <E > listIterator () {
298- return (ListIterator <E >)new Itr (false , 0 , 0 , 0 );
320+ return (ListIterator <E >) new Itr (false , 0 , 0 , 0 );
299321 }
300322
301323 /**
302324 * Returns a list iterator over the elements in this model (in proper
303325 * sequence), starting at the specified position in the model.
326+ *
304327 * @param index index of the first element to be returned from the
305328 * list iterator (by a call to {@link ListIterator#next next}).
306329 * @return a list iterator over the elements in this model (in proper
@@ -318,19 +341,22 @@ protected ListIterator<E> listIterator(int index) {
318341 Source source = sources [sourceIndex ];
319342 int localSize = source .size ();
320343 if (localIndex < localSize )
321- return (ListIterator <E >)new Itr (false , sourceIndex , localIndex , index );
344+ return (ListIterator <E >) new Itr (false , sourceIndex , localIndex , index );
322345 localIndex -= localSize ;
323346 }
347+ if (localIndex == 0 )
348+ return new Itr (false , nSources , 0 , index );
324349 throw new IndexOutOfBoundsException ();
325350 }
326351
327352 /**
328353 * Returns a list iterator over the <b>entries</b> in this model (in proper sequence).
354+ *
329355 * @return a list iterator over the <b>entries</b> in this model (in proper sequence).
330356 */
331357 @ SuppressWarnings ("unchecked" )
332358 protected ListIterator <N > entryListIterator () {
333- return (ListIterator <N >)new Itr (true , 0 , 0 , 0 );
359+ return (ListIterator <N >) new Itr (true , 0 , 0 , 0 );
334360 }
335361
336362 // ================================== protected for override ==================================
@@ -372,8 +398,9 @@ private void notifyChanged(boolean trimToSize) {
372398 modelChanged (changedEntries );
373399 } finally {
374400 // cleanup internal state even if listeners crash
375- for (Entry <E > entry : changedEntries )
401+ for (Entry <E > entry : changedEntries ) {
376402 entry .commitChange ();
403+ }
377404 changedEntries .clear ();
378405 if (trimToSize )
379406 changedEntries .trimToSize (); // Don't need memory we held for snapshot -- let GC do its work
@@ -387,12 +414,13 @@ private Source getSourceById(int sourceId) {
387414 int m = (i + j ) >> 1 ;
388415 Source mSource = sources [m ];
389416 int mSourceId = mSource .sourceId ;
390- if (sourceId < mSourceId )
417+ if (sourceId < mSourceId ) {
391418 j = m ;
392- else if (sourceId > mSourceId )
419+ } else if (sourceId > mSourceId ) {
393420 i = m + 1 ;
394- else
421+ } else {
395422 return mSource ;
423+ }
396424 }
397425 if (nSources == sources .length )
398426 sources = Arrays .copyOf (sources , sources .length << 1 );
@@ -435,8 +463,9 @@ private void enforceSizeLimit() {
435463 int size = size ();
436464 int sourceIndex = 0 ;
437465 while (size > sizeLimit ) {
438- while (sources [sourceIndex ].isEmpty ())
466+ while (sources [sourceIndex ].isEmpty ()) {
439467 sourceIndex ++;
468+ }
440469 sources [sourceIndex ].removeImpl (0 );
441470 size --;
442471 }
@@ -520,14 +549,15 @@ void processEvent(E event) {
520549 return ; // nothing to do on remove on non-existing
521550 // insert new entry if not found
522551 N entry ;
523- if (a >= 0 ) // found entry -- use
552+ if (a >= 0 ) { // found entry -- use
524553 entry = get (a );
525- else // not found -- insert new one
554+ } else { // not found -- insert new one
526555 insertImpl (-a - 1 , entry = createEntry ());
556+ }
527557 makeChanged (entry );
528- if (remove )
558+ if (remove ) {
529559 removeImpl (a ); // remove existing entry ("removed" method will set null value)
530- else {
560+ } else {
531561 event .setEventFlags (0 ); // cleanup the flags in the stored event
532562 entry .newValue = event ;
533563 }
0 commit comments