gt:         synchronized (traRecLock) {
context: /*
   * Copyright (c) 1999, 2019, 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.media.sound;
  
  import java.util.ArrayList;
  import java.util.Collections;
  import java.util.List;
  
  import javax.sound.midi.InvalidMidiDataException;
  import javax.sound.midi.MidiDevice;
  import javax.sound.midi.MidiDeviceReceiver;
  import javax.sound.midi.MidiDeviceTransmitter;
  import javax.sound.midi.MidiMessage;
  import javax.sound.midi.MidiUnavailableException;
  import javax.sound.midi.Receiver;
  import javax.sound.midi.Transmitter;
  
  
  /**
   * Abstract AbstractMidiDevice class representing functionality shared by
   * MidiInDevice and MidiOutDevice objects.
   *
   * @author David Rivas
   * @author Kara Kytle
   * @author Matthias Pfisterer
   * @author Florian Bomers
   */
  abstract class AbstractMidiDevice implements MidiDevice, ReferenceCountingDevice {
  
      private ArrayList<Receiver> receiverList;
  
      private TransmitterList transmitterList;
  
      // lock to protect receiverList and transmitterList
      // from simultaneous creation and destruction
      // reduces possibility of deadlock, compared to
      // synchronizing to the class instance
      private final Object traRecLock = new Object();
  
      // DEVICE ATTRIBUTES
  
      private final MidiDevice.Info info;
  
      // DEVICE STATE
  
      private volatile boolean open;
      private int openRefCount;
  
      /** List of Receivers and Transmitters that opened the device implicitely.
       */
      private List<Object> openKeepingObjects;
  
      /**
       * This is the device handle returned from native code.
       */
      protected volatile long id;
  
      /**
       * Constructs an AbstractMidiDevice with the specified info object.
       * @param info the description of the device
       */
      /*
       * The initial mode and only supported mode default to OMNI_ON_POLY.
       */
      protected AbstractMidiDevice(MidiDevice.Info info) {
          this.info = info;
          openRefCount = 0;
      }
  
      // MIDI DEVICE METHODS
  
      @Override
      public final MidiDevice.Info getDeviceInfo() {
          return info;
      }
  
      /** Open the device from an application program.
       * Setting the open reference count to -1 here prevents Transmitters and Receivers that
       * opened the device implicitly from closing it. The only way to close the device after
       * this call is a call to close().
       */
      @Override
      public final void open() throws MidiUnavailableException {
          synchronized(this) {
              openRefCount = -1;
              doOpen();
          }
      }
  
      /** Open the device implicitly.
       * This method is intended to be used by AbstractReceiver
       * and BasicTransmitter. Actually, it is called by getReceiverReferenceCounting() and
       * getTransmitterReferenceCounting(). These, in turn, are called by MidiSytem on calls to
       * getReceiver() and getTransmitter(). The former methods should pass the Receiver or
       * Transmitter just created as the object parameter to this method. Storing references to
       * these objects is necessary to be able to decide later (when it comes to closing) if
       * R/T's are ones that opened the device implicitly.
       *
       * @object The Receiver or Transmitter instance that triggered this implicit open.
       */
      private void openInternal(Object object) throws MidiUnavailableException {
          synchronized(this) {
              if (openRefCount != -1) {
                  openRefCount++;
                  getOpenKeepingObjects().add(object);
              }
              // double calls to doOpens() will be catched by the open flag.
              doOpen();
          }
      }
  
      private void doOpen() throws MidiUnavailableException {
          synchronized(this) {
              if (! isOpen()) {
                  implOpen();
                  open = true;
              }
          }
      }
  
      @Override
      public final void close() {
          synchronized (this) {
              doClose();
              openRefCount = 0;
          }
      }
  
      /** Close the device for an object that implicitely opened it.
       * This method is intended to be used by Transmitter.close() and Receiver.close().
       * Those methods should pass this for the object parameter. Since Transmitters or Receivers
       * do not know if their device has been opened implicitely because of them, they call this
       * method in any case. This method now is able to seperate Receivers/Transmitters that opened
       * the device implicitely from those that didn't by looking up the R/T in the
       * openKeepingObjects list. Only if the R/T is contained there, the reference count is
       * reduced.
       *
       * @param object The object that might have been opening the device implicitely (for now,
       * this may be a Transmitter or receiver).
       */
      public final void closeInternal(Object object) {
          synchronized(this) {
              if (getOpenKeepingObjects().remove(object)) {
                  if (openRefCount > 0) {
                      openRefCount--;
                      if (openRefCount == 0) {
                          doClose();
                      }
                  }
              }
          }
      }
  
      public final void doClose() {
          synchronized(this) {
              if (isOpen()) {
                  implClose();
                  open = false;
              }
          }
      }
  
      @Override
      public final boolean isOpen() {
          return open;
      }
  
      protected void implClose() {
          synchronized (traRecLock) {
              if (receiverList != null) {
                  // close all receivers
                  for(int i = 0; i < receiverList.size(); i++) {
                      receiverList.get(i).close();
                  }
                  receiverList.clear();
              }
              if (transmitterList != null) {
                  // close all transmitters
                  transmitterList.close();
              }
          }
      }
  
      /**
       * This implementation always returns -1.
       * Devices that actually provide this should over-ride
       * this method.
       */
      @Override
      public long getMicrosecondPosition() {
          return -1;
      }
  
      /** Return the maximum number of Receivers supported by this device.
          Depending on the return value of hasReceivers(), this method returns either 0 or -1.
          Subclasses should rather override hasReceivers() than override this method.
       */
      @Override
      public final int getMaxReceivers() {
          if (hasReceivers()) {
              return -1;
          } else {
              return 0;
          }
      }
  
      /** Return the maximum number of Transmitters supported by this device.
          Depending on the return value of hasTransmitters(), this method returns either 0 or -1.
          Subclasses should override hasTransmitters().
       */
      @Override
      public final int getMaxTransmitters() {
          if (hasTransmitters()) {
              return -1;
          } else {
              return 0;
          }
      }
  
      /** Retrieve a Receiver for this device.
          This method returns the value returned by createReceiver(), if it doesn't throw
          an exception. Subclasses should rather override createReceiver() than override
          this method.
          If createReceiver returns a Receiver, it is added to the internal list
          of Receivers (see getReceiversList)
       */
      @Override
      public final Receiver getReceiver() throws MidiUnavailableException {
          Receiver receiver;
          synchronized (traRecLock) {
              receiver = createReceiver(); // may throw MidiUnavailableException
              getReceiverList().add(receiver);
          }
          return receiver;
      }
  
      @Override
      @SuppressWarnings("unchecked") // Cast of result of clone
      public final List<Receiver> getReceivers() {
          List<Receiver> recs;
          synchronized (traRecLock) {
              if (receiverList == null) {
                  recs = Collections.unmodifiableList(new ArrayList<Receiver>(0));
              } else {
                  recs = Collections.unmodifiableList
                      ((List<Receiver>) (receiverList.clone()));
              }
          }
          return recs;
      }
  
      /**
       * This implementation uses createTransmitter, which may throw an exception.
       * If a transmitter is returned in createTransmitter, it is added to the internal
       * TransmitterList
       */
      @Override
      public final Transmitter getTransmitter() throws MidiUnavailableException {
          Transmitter transmitter;
          synchronized (traRecLock) {
              transmitter = createTransmitter(); // may throw MidiUnavailableException
              getTransmitterList().add(transmitter);
          }
          return transmitter;
      }
  
      @Override
      @SuppressWarnings("unchecked") // Cast of result of clone
      public final List<Transmitter> getTransmitters() {
          List<Transmitter> tras;
  