content: /*
   *                         Vortex OpenSplice
   *
   *   This software and documentation are Copyright 2006 to TO_YEAR ADLINK
   *   Technology Limited, its affiliated companies and licensors. All rights
   *   reserved.
   *
   *   Licensed under the Apache License, Version 2.0 (the "License");
   *   you may not use this file except in compliance with the License.
   *   You may obtain a copy of the License at
   *
   *       http://www.apache.org/licenses/LICENSE-2.0
   *
   *   Unless required by applicable law or agreed to in writing, software
   *   distributed under the License is distributed on an "AS IS" BASIS,
   *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   *   See the License for the specific language governing permissions and
   *   limitations under the License.
   *
   */
  package org.opensplice.dds.core;
  
  import java.util.EventListener;
  import java.util.Set;
  import java.util.concurrent.atomic.AtomicInteger;
  
  import org.eclipse.cyclone.dds.core.AbstractDDSObject;
  import org.omg.dds.core.EntityQos;
  import org.omg.dds.core.InstanceHandle;
  import org.omg.dds.core.ServiceEnvironment;
  import org.omg.dds.core.status.Status;
  import org.opensplice.dds.core.status.StatusConverter;
  
  public abstract class EntityImpl<OLD extends DDS.Entity, OLDPARENT, QOS extends EntityQos<?>, LISTENER extends EventListener, LISTENERIMPL extends Listener<LISTENER>>
          extends AbstractDDSObject implements org.omg.dds.core.Entity<LISTENER, QOS>, Properties {
      protected final transient OsplServiceEnvironment environment;
      private final OLDPARENT oldParent;
      private OLD old;
      protected LISTENERIMPL listener;
      private AtomicInteger refCount;
      private static java.util.HashMap<String, Integer> references = new java.util.HashMap<String, Integer>();
  
      private static boolean addReference(String name) {
          synchronized (references) {
              Integer refs = references.get(name);
  
              if (refs == null) {
                  references.put(name, 1);
              } else {
                  references.put(name, refs.intValue() + 1);
              }
          }
          return true;
      }
  
      private static boolean removeReference(String name) {
          synchronized (references) {
              Integer refs = references.get(name);
  
              assert (refs != null);
              references.put(name, refs.intValue() - 1);
          }
          return true;
      }
  
      public static boolean printReferences() {
          boolean noMoreRefs = true;
  
          synchronized (references) {
              for (String name : references.keySet()) {
                  int count = references.get(name);
                  if (count != 0) {
                      noMoreRefs = false;
                  }
                  System.out.println(name + "=" + count);
              }
              if (!noMoreRefs) {
                  System.out.println("----------------");
  
                  for (String name : references.keySet()) {
                      int count = references.get(name);
                      if (count != 0) {
                          noMoreRefs = false;
                      }
                      System.out.println(name + "=" + count);
                  }
                  System.out.println("----------------");
              }
          }
          return noMoreRefs;
      }
  
      public EntityImpl(OsplServiceEnvironment environment, OLDPARENT oldParent) {
          this.environment = environment;
          this.oldParent = oldParent;
          this.listener = null;
          this.refCount = new AtomicInteger(1);
  
          assert (addReference(this.getClass().getSimpleName()));
      }
  
      public OLD getOld() {
          final OLD old = this.old;
  
          if (old == null) {
              throw new AlreadyClosedExceptionImpl(this.environment,
                      "Entity already closed.");
          }
          return old;
      }
  
      protected void setOld(OLD old) {
          this.old = old;
      }
  
      public OLDPARENT getOldParent() {
          return this.oldParent;
      }
  
      @Override
      public ServiceEnvironment getEnvironment() {
          return this.environment;
      }
  
      @Override
      public final void retain() {
          int newValue = this.refCount.incrementAndGet();
  
          if (newValue <= 0) {
              int refCount = this.refCount.decrementAndGet();
              throw new AlreadyClosedExceptionImpl(this.environment,
                      "Entity already closed. refcount:" + refCount);
          }
          assert (newValue > newValue - 1);
          assert (newValue > 1);
      }
  
      @Override
      public final void close() {
          int newValue = this.refCount.decrementAndGet();
  
          if (newValue == 0) {
              this.destroy();
              this.old = null;
              assert (removeReference(this.getClass().getSimpleName()));
          } else if (newValue < 0) {
              throw new AlreadyClosedExceptionImpl(this.environment,
                      "Entity already closed.");
          }
      }
  
      @Override
      public final void enable() {
          int rc = this.old.enable();
          Utilities.checkReturnCode(rc, this.environment,
                  "Entity.enable() failed.");
      }
  
      @Override
      public final Set<Class<? extends Status>> getStatusChanges() {
          return StatusConverter.convertMask(this.environment,
                  this.old.get_status_changes());
      }
  
      @Override
      public final InstanceHandle getInstanceHandle() {
          return new InstanceHandleImpl(this.environment,
                  old.get_instance_handle());
      }
  
      protected abstract void destroy();
  
      @Override
      public final LISTENER getListener(){
          if (this.listener != null) {
              return this.listener.getRealListener();
          }
          return null;
      }
  
      @Override
      public void setProperty(String key, String value) {
          int rc = this.old.set_property(new DDS.Property(key, value));
          Utilities.checkReturnCode(rc, this.environment,
                  "Properties.setProperty() failed.");
      }
  
      @Override
      public String getProperty(String key) {
          DDS.PropertyHolder holder = new DDS.PropertyHolder();
          holder.value = new DDS.Property(key, null);
          int rc = this.old.get_property(holder);
          Utilities.checkReturnCode(rc, this.environment,
                  "Properties.getProperty() failed.");
          return holder.value.value;
      }
  }
  