gt:                 if (locked) {
context: /*
   * Copyright (c) 2011, 2013, Oracle and/or its affiliates. All rights reserved.
   * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   *
   * This code is free software; you can redistribute it and/or modify it
   * under the terms of the GNU General Public License version 2 only, as
   * published by the Free Software Foundation.  Oracle designates this
   * particular file as subject to the "Classpath" exception as provided
   * by Oracle in the LICENSE file that accompanied this code.
   *
   * This code is distributed in the hope that it will be useful, but WITHOUT
   * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
   * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
   * version 2 for more details (a copy is included in the LICENSE file that
   * accompanied this code).
   *
   * You should have received a copy of the GNU General Public License version
   * 2 along with this work; if not, write to the Free Software Foundation,
   * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
   *
   * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
   * or visit www.oracle.com if you need additional information or have any
   * questions.
   */
  
  package com.sun.javafx.binding;
  
  import com.sun.javafx.collections.NonIterableChange;
  import javafx.beans.InvalidationListener;
  import javafx.beans.value.ChangeListener;
  import javafx.beans.value.ObservableListValue;
  import javafx.collections.FXCollections;
  import javafx.collections.ListChangeListener;
  import javafx.collections.ObservableList;
  
  import java.util.Arrays;
  import java.util.List;
  
  import static javafx.collections.ListChangeListener.Change;
  
  /**
   * A convenience class for creating implementations of {@link javafx.beans.value.ObservableValue}.
   * It contains all of the infrastructure support for value invalidation- and
   * change event notification.
   * 
   * This implementation can handle adding and removing listeners while the
   * observers are being notified, but it is not thread-safe.
   * 
   * 
   */
  public abstract class ListExpressionHelper<E> extends ExpressionHelperBase {
  
  
      ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
      // Static methods
  
      public static <E> ListExpressionHelper<E> addListener(ListExpressionHelper<E> helper, ObservableListValue<E> observable, InvalidationListener listener) {
          if ((observable == null) || (listener == null)) {
              throw new NullPointerException();
          }
          observable.getValue(); // validate observable
          return (helper == null)? new SingleInvalidation<E>(observable, listener) : helper.addListener(listener);
      }
  
      public static <E> ListExpressionHelper<E> removeListener(ListExpressionHelper<E> helper, InvalidationListener listener) {
          if (listener == null) {
              throw new NullPointerException();
          }
          return (helper == null)? null : helper.removeListener(listener);
      }
  
      public static <E> ListExpressionHelper<E> addListener(ListExpressionHelper<E> helper, ObservableListValue<E> observable, ChangeListener<? super ObservableList<E>> listener) {
          if ((observable == null) || (listener == null)) {
              throw new NullPointerException();
          }
          return (helper == null)? new SingleChange<E>(observable, listener) : helper.addListener(listener);
      }
  
      public static <E> ListExpressionHelper<E> removeListener(ListExpressionHelper<E> helper, ChangeListener<? super ObservableList<E>> listener) {
          if (listener == null) {
              throw new NullPointerException();
          }
          return (helper == null)? null : helper.removeListener(listener);
      }
  
      public static <E> ListExpressionHelper<E> addListener(ListExpressionHelper<E> helper, ObservableListValue<E> observable, ListChangeListener<? super E> listener) {
          if ((observable == null) || (listener == null)) {
              throw new NullPointerException();
          }
          return (helper == null)? new SingleListChange<E>(observable, listener) : helper.addListener(listener);
      }
  
      public static <E> ListExpressionHelper<E> removeListener(ListExpressionHelper<E> helper, ListChangeListener<? super E> listener) {
          if (listener == null) {
              throw new NullPointerException();
          }
          return (helper == null)? null : helper.removeListener(listener);
      }
  
      public static <E> void fireValueChangedEvent(ListExpressionHelper<E> helper) {
          if (helper != null) {
              helper.fireValueChangedEvent();
          }
      }
  
      public static <E> void fireValueChangedEvent(ListExpressionHelper<E> helper, Change<? extends E> change) {
          if (helper != null) {
              helper.fireValueChangedEvent(change);
          }
      }
  
      ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
      // Common implementations
  
      protected final ObservableListValue<E> observable;
  
      protected ListExpressionHelper(ObservableListValue<E> observable) {
          this.observable = observable;
      }
  
      protected abstract ListExpressionHelper<E> addListener(InvalidationListener listener);
      protected abstract ListExpressionHelper<E> removeListener(InvalidationListener listener);
  
      protected abstract ListExpressionHelper<E> addListener(ChangeListener<? super ObservableList<E>> listener);
      protected abstract ListExpressionHelper<E> removeListener(ChangeListener<? super ObservableList<E>> listener);
  
      protected abstract ListExpressionHelper<E> addListener(ListChangeListener<? super E> listener);
      protected abstract ListExpressionHelper<E> removeListener(ListChangeListener<? super E> listener);
  
      protected abstract void fireValueChangedEvent();
      protected abstract void fireValueChangedEvent(Change<? extends E> change);
  
      ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
      // Implementations
  
      private static class SingleInvalidation<E> extends ListExpressionHelper<E> {
  
          private final InvalidationListener listener;
  
          private SingleInvalidation(ObservableListValue<E> observable, InvalidationListener listener) {
              super(observable);
              this.listener = listener;
          }
  
          @Override
          protected ListExpressionHelper<E> addListener(InvalidationListener listener) {
              return new Generic<E>(observable, this.listener, listener);
          }
  
          @Override
          protected ListExpressionHelper<E> removeListener(InvalidationListener listener) {
              return (listener.equals(this.listener))? null : this;
          }
  
          @Override
          protected ListExpressionHelper<E> addListener(ChangeListener<? super ObservableList<E>> listener) {
              return new Generic<E>(observable, this.listener, listener);
          }
  
          @Override
          protected ListExpressionHelper<E> removeListener(ChangeListener<? super ObservableList<E>> listener) {
              return this;
          }
  
          @Override
          protected ListExpressionHelper<E> addListener(ListChangeListener<? super E> listener) {
              return new Generic<E>(observable, this.listener, listener);
          }
  
          @Override
          protected ListExpressionHelper<E> removeListener(ListChangeListener<? super E> listener) {
              return this;
          }
  
          @Override
          protected void fireValueChangedEvent() {
              listener.invalidated(observable);
          }
  
          @Override
          protected void fireValueChangedEvent(Change<? extends E> change) {
              listener.invalidated(observable);
          }
      }
  
      private static class SingleChange<E> extends ListExpressionHelper<E> {
  
          private final ChangeListener<? super ObservableList<E>> listener;
          private ObservableList<E> currentValue;
  
          private SingleChange(ObservableListValue<E> observable, ChangeListener<? super ObservableList<E>> listener) {
              super(observable);
              this.listener = listener;
              this.currentValue = observable.getValue();
          }
  
          @Override
          protected ListExpressionHelper<E> addListener(InvalidationListener listener) {
              return new Generic<E>(observable, listener, this.listener);
          }
  
          @Override
          protected ListExpressionHelper<E> removeListener(InvalidationListener listener) {
              return this;
          }
  
          @Override
          protected ListExpressionHelper<E> addListener(ChangeListener<? super ObservableList<E>> listener) {
              return new Generic<E>(observable, this.listener, listener);
          }
  
          @Override
          protected ListExpressionHelper<E> removeListener(ChangeListener<? super ObservableList<E>> listener) {
              return (listener.equals(this.listener))? null : this;
          }
  
          @Override
          protected ListExpressionHelper<E> addListener(ListChangeListener<? super E> listener) {
              return new Generic<E>(observable, this.listener, listener);
          }
  
          @Override
          protected ListExpressionHelper<E> removeListener(ListChangeListener<? super E> listener) {
              return this;
          }
  
          @Override
          protected void fireValueChangedEvent() {
              final ObservableList<E> oldValue = currentValue;
              currentValue = observable.getValue();
              if (currentValue != oldValue) {
                  listener.changed(observable, oldValue, currentValue);
              }
          }
  
          @Override
          protected void fireValueChangedEvent(Change<? extends E> change) {
              listener.changed(observable, currentValue, currentValue);
          }
      }
  
      private static class SingleListChange<E> extends ListExpressionHelper<E> {
  
          private final ListChangeListener<? super E> listener;
          private ObservableList<E> currentValue;
  
          private SingleListChange(ObservableListValue<E> observable, ListChangeListener<? super E> listener) {
              super(observable);
              this.listener = listener;
              this.currentValue = observable.getValue();
          }
  
          @Override
          protected ListExpressionHelper<E> addListener(InvalidationListener listener) {
              return new Generic<E>(observable, listener, this.listener);
          }
  
          @Override
          protected ListExpressionHelper<E> removeListener(InvalidationListener listener) {
              return this;
          }
  
          @Override
          protected ListExpressionHelper<E> addListener(ChangeListener<? super ObservableList<E>> listener) {
              return new Generic<E>(observable, listener, this.listener);
          }
  
          @Override
          protected ListExpressionHelper<E> removeListener(ChangeListener<? super ObservableList<E>> listener) {
              return this;
          }
  
          @Override
          protected ListExpressionHelper<E> addListener(ListChangeListener<? super E> listener) {
              return new Generic<E>(observable, this.listener, listener);
          }
  
          @Override
          protected ListExpressionHelper<E> removeListener(ListChangeListener<? super E> listener) {
              return (listener.equals(this.listener))? null : this;
          }
  
          @Override
          protected void fireValueChangedEvent() {
              final ObservableList<E> oldValue = currentValue;
              currentValue = observable.getValue();
              if (currentValue != oldValue) {
                  final int safeSize = (currentValue == null)? 0 : currentValue.size();
                  final ObservableList<E> safeOldValue = (oldValue == null)? 
                          FXCollections.<E>emptyObservableList() 
                          : FXCollections.unmodifiableObservableList(oldValue);
                  final Change<E> change = new NonIterableChange.GenericAddRemoveChange<E>(0, safeSize, safeOldValue, observable);
                  listener.onChanged(change);
              }
          }
  
          @Override
          protected void fireValueChangedEvent(final Change<? extends E> change) {
              listener.onChanged(new MappedChange<E>(observable, change));
          }
      }
  
      private static class Generic<E> extends ListExpressionHelper<E> {
  
          private InvalidationListener[] invalidationListeners;
          private ChangeListener<? super ObservableList<E>>[] changeListeners;
          private ListChangeListener<? super E>[] listChangeListeners;
          private int invalidationSize;
          private int changeSize;
          private int listChangeSize;
          private boolean locked;
          private ObservableList<E> currentValue;
  
          private Generic(ObservableListValue<E> observable, InvalidationListener listener0, InvalidationListener listener1) {
              super(observable);
              this.invalidationListeners = new InvalidationListener[] {listener0, listener1};
              this.invalidationSize = 2;
          }
  
          private Generic(ObservableListValue<E> observable, ChangeListener<? super ObservableList<E>> listener0, ChangeListener<? super ObservableList<E>> listener1) {
              super(observable);
              this.changeListeners = new ChangeListener[] {listener0, listener1};
              this.changeSize = 2;
              this.currentValue = observable.getValue();
          }
  
          private Generic(ObservableListValue<E> observable, ListChangeListener<? super E> listener0, ListChangeListener<? super E> listener1) {
              super(observable);
              this.listChangeListeners = new ListChangeListener[] {listener0, listener1};
              this.listChangeSize = 2;
              this.currentValue = observable.getValue();
          }
  
          private Generic(ObservableListValue<E> observable, InvalidationListener invalidationListener, ChangeListener<? super ObservableList<E>> changeListener) {
              super(observable);
              this.invalidationListeners = new InvalidationListener[] {invalidationListener};
              this.invalidationSize = 1;
              this.changeListeners = new ChangeListener[] {changeListener};
              this.changeSize = 1;
              this.currentValue = observable.getValue();
          }
  
          private Generic(ObservableListValue<E> observable, InvalidationListener invalidationListener, ListChangeListener<? super E> listChangeListener) {
              super(observable);
              this.invalidationListeners = new InvalidationListener[] {invalidationListener};
              this.invalidationSize = 1;
              this.listChangeListeners = new ListChangeListener[] {listChangeListener};
              this.listChangeSize = 1;
              this.currentValue = observable.getValue();
          }
  
          private Generic(ObservableListValue<E> observable, ChangeListener<? super ObservableList<E>> changeListener, ListChangeListener<? super E> listChangeListener) {
              super(observable);
              this.changeListeners = new ChangeListener[] {changeListener};
              this.changeSize = 1;
              this.listChangeListeners = new ListChangeListener[] {listChangeListener};
              this.listChangeSize = 1;
              this.currentValue = observable.getValue();
          }
  
          @Override
          protected ListExpressionHelper<E> addListener(InvalidationListener listener) {
              if (invalidationListeners == null) {
                  invalidationListeners = new InvalidationListener[] {listener};
                  invalidationSize = 1;
              } else {
                  final int oldCapacity = invalidationListeners.length;
                  if (locked) {
                      final int newCapacity = (invalidationSize < oldCapacity)? oldCapacity : (oldCapacity * 3)/2 + 1;
                      invalidationListeners = Arrays.copyOf(invalidationListeners, newCapacity);
                  } else if (invalidationSize == oldCapacity) {
                      invalidationSize = trim(invalidationSize, invalidationListeners);
                      if (invalidationSize == oldCapacity) {
                          final int newCapacity = (oldCapacity * 3)/2 + 1;
                          invalidationListeners = Arrays.copyOf(invalidationListeners, newCapacity);
                      }
                  }
                  invalidationListeners[invalidationSize++] = listener;
              }
              return this;
          }
  
          @Override
          protected ListExpressionHelper<E> removeListener(InvalidationListener listener) {
              if (invalidationListeners != null) {
                  for (int index = 0; index < invalidationSize; index++) {
                      if (listener.equals(invalidationListeners[index])) {
                          if (invalidationSize == 1) {
                              if ((changeSize == 1) && (listChangeSize == 0)) {
                                  return new SingleChange<E>(observable, changeListeners[0]);
                              } else if ((changeSize == 0) && (listChangeSize == 1)) {
                                  return new SingleListChange<E>(observable, listChangeListeners[0]);
                              }
                              invalidationListeners = null;
                              invalidationSize = 0;
                          } else if ((invalidationSize == 2) && (changeSize == 0) && (listChangeSize == 0)) {
                              return new SingleInvalidation<E>(observable, invalidationListeners[1-index]);
                          } else {
                              final int numMoved = invalidationSize - index - 1;
                              final InvalidationListener[] oldListeners = invalidationListeners;
                              if (locked) {
                                  invalidationListeners = new InvalidationListener[invalidationListeners.length];
                                  System.arraycopy(oldListeners, 0, invalidationListeners, 0, index+1);
                              }
                              if (numMoved > 0) {
                                  System.arraycopy(oldListeners, index+1, invalidationListeners, index, numMoved);
                              }
                              invalidationSize--;
                              if (!locked) {
                                  invalidationListeners[invalidationSize] = null; // Let gc do its work
                              }
                          }
                          break;
                      }
                  }
              }
              return this;
          }
  
          @Override
          protected ListExpressionHelper<E> addListener(ChangeListener<? super ObservableList<E>> listener) {
              if (changeListeners == null) {
                  changeListeners = new ChangeListener[] {listener};
                  changeSize = 1;
              } else {
                  final int oldCapacity = changeListeners.length;
                  if (locked) {
                      final int newCapacity = (changeSize < oldCapacity)? oldCapacity : (oldCapacity * 3)/2 + 1;
                      changeListeners = Arrays.copyOf(changeListeners, newCapacity);
                  } else if (changeSize == oldCapacity) {
                      changeSize = trim(changeSize, changeListeners);
                      if (changeSize == oldCapacity) {
                          final int newCapacity = (oldCapacity * 3)/2 + 1;
                          changeListeners = Arrays.copyOf(changeListeners, newCapacity);
                      }
                  }
                  changeListeners[changeSize++] = listener;
              }
              if (changeSize == 1) {
                  currentValue = observable.getValue();
              }
              return this;
          }
  
          @Override
          protected ListExpressionHelper<E> removeListener(ChangeListener<? super ObservableList<E>> listener) {
              if (changeListeners != null) {
                  for (int index = 0; index < changeSize; index++) {
                      if (listener.equals(changeListeners[index])) {
                          if (changeSize == 1) {
                              if ((invalidationSize == 1) && (listChangeSize == 0)) {
                                  return new SingleInvalidation<E>(observable, invalidationListeners[0]);
                              } else if ((invalidationSize == 0) && (listChangeSize == 1)) {
                                  return new SingleListChange<E>(observable, listChangeListeners[0]);
                              }
                              changeListeners = null;
                              changeSize = 0;
                          } else if ((changeSize == 2) && (invalidationSize == 0) && (listChangeSize == 0)) {
                              return new SingleChange<E>(observable, changeListeners[1-index]);
                          } else {
                              final int numMoved = changeSize - index - 1;
                              final ChangeListener<? super ObservableList<E>>[] oldListeners = changeListeners;
                              if (locked) {
                                  changeListeners = new ChangeListener[changeListeners.length];
                                  System.arraycopy(oldListeners, 0, changeListeners, 0, index+1);
                              }
                              if (numMoved > 0) {
                                  System.arraycopy(oldListeners, index+1, changeListeners, index, numMoved);
                              }
                              changeSize--;
                              if (!locked) {
                                  changeListeners[changeSize] = null; // Let gc do its work
                              }
                          }
                          break;
                      }
                  }
              }
              return this;
          }
  
          @Override
          protected ListExpressionHelper<E> addListener(ListChangeListener<? super E> listener) {
              if (listChangeListeners == null) {
                  listChangeListeners = new ListChangeListener[] {listener};
                  listChangeSize = 1;
              } else {
                  final int oldCapacity = listChangeListeners.length;
  