/**
  * Added for bug 45749. The attributes in pa are merged into this. Only attributes explicitly set
  * in pa will be merged into this. Any attribute set in pa will take precedence over an attribute
  * in this.
  *
  * @param pa the attributes to merge into this.
  * @since 7.0
  */
 public void merge(PartitionAttributesImpl pa) {
   if (pa.hasRedundancy) {
     setRedundantCopies(pa.getRedundantCopies());
   }
   if (pa.hasLocalMaxMemory) {
     setLocalMaxMemory(pa.getLocalMaxMemory());
   }
   if (pa.hasOffHeap) {
     setOffHeap(pa.getOffHeap());
   }
   if (pa.hasTotalMaxMemory) {
     setTotalMaxMemory(pa.getTotalMaxMemory());
   }
   if (pa.hasTotalNumBuckets) {
     setTotalNumBuckets(pa.getTotalNumBuckets());
   }
   if (pa.hasPartitionResolver) {
     setPartitionResolver(pa.getPartitionResolver());
   }
   if (pa.hasColocatedRegionName) {
     setColocatedWith(pa.getColocatedWith());
   }
   if (pa.hasRecoveryDelay) {
     setRecoveryDelay(pa.getRecoveryDelay());
   }
   if (pa.hasStartupRecoveryDelay) {
     setStartupRecoveryDelay(pa.getStartupRecoveryDelay());
   }
   if (pa.hasFixedPAttrs) {
     addFixedPartitionAttributes(pa.getFixedPartitionAttributes());
   }
   if (pa.hasPartitionListeners) {
     this.addPartitionListeners(pa.partitionListeners);
   }
 }
 @Override
 public void fromData(DataInput in) throws IOException, ClassNotFoundException {
   this.prId = in.readInt();
   this.scope = Scope.fromOrdinal(in.readByte());
   this.pAttrs = PartitionAttributesImpl.createFromData(in);
   this.isDestroying = in.readBoolean();
   this.isColocationComplete = in.readBoolean();
   this.nodes = new VersionedArrayList();
   InternalDataSerializer.invokeFromData(this.nodes, in);
   this.partitionResolver = DataSerializer.readString(in);
   this.colocatedWith = DataSerializer.readString(in);
   this.fullPath = DataSerializer.readString(in);
   this.ea = EvictionAttributesImpl.createFromData(in);
   this.regionIdleTimeout = ExpirationAttributes.createFromData(in);
   this.regionTimeToLive = ExpirationAttributes.createFromData(in);
   this.entryIdleTimeout = ExpirationAttributes.createFromData(in);
   this.entryTimeToLive = ExpirationAttributes.createFromData(in);
   this.firstDataStoreCreated = in.readBoolean();
   this.elderFPAs = DataSerializer.readObject(in);
   if (this.elderFPAs == null) {
     this.elderFPAs = new LinkedHashSet<FixedPartitionAttributesImpl>();
   }
   this.partitionListenerClassNames = DataSerializer.readArrayList(in);
   this.gatewaySenderIds = DataSerializer.readObject(in);
   if (this.gatewaySenderIds == null) {
     this.gatewaySenderIds = Collections.emptySet();
   }
 }
 @Override
 public Object clone() {
   try {
     PartitionAttributesImpl copy = (PartitionAttributesImpl) super.clone();
     if (copy.fixedPAttrs != null) {
       copy.fixedPAttrs = new ArrayList<FixedPartitionAttributesImpl>(copy.fixedPAttrs);
     }
     if (copy.partitionListeners != null) {
       copy.partitionListeners = new ArrayList<PartitionListener>(copy.partitionListeners);
     }
     return copy;
   } catch (CloneNotSupportedException e) {
     throw new InternalGemFireError(
         LocalizedStrings
             .PartitionAttributesImpl_CLONENOTSUPPORTEDEXCEPTION_THROWN_IN_CLASS_THAT_IMPLEMENTS_CLONEABLE
             .toLocalizedString());
   }
 }
  @Override
  public boolean equals(final Object obj) {
    if (this == obj) {
      return true;
    }

    if (!(obj instanceof PartitionAttributesImpl)) {
      return false;
    }

    PartitionAttributesImpl other = (PartitionAttributesImpl) obj;

    if (this.redundancy != other.getRedundantCopies()
        || getLocalMaxMemory() != other.getLocalMaxMemory()
        || this.offHeap != other.getOffHeap()
        || this.totalNumBuckets != other.getTotalNumBuckets()
        || this.totalMaxMemory != other.getTotalMaxMemory()
        || this.startupRecoveryDelay != other.getStartupRecoveryDelay()
        || this.recoveryDelay != other.getRecoveryDelay()
        //          || ! this.localProperties.equals(other.getLocalProperties())
        //          || ! this.globalProperties.equals(other.getGlobalProperties())
        || ((this.partitionResolver == null) != (other.getPartitionResolver() == null))
        || (this.partitionResolver != null
            && !this.partitionResolver.equals(other.getPartitionResolver()))
        || ((this.colocatedRegionName == null) != (other.getColocatedWith() == null))
        || (this.colocatedRegionName != null
            && !this.colocatedRegionName.equals(other.getColocatedWith()))
        || ((this.fixedPAttrs == null) != (other.getFixedPartitionAttributes() == null))
        || (this.fixedPAttrs != null
            && !this.fixedPAttrs.equals(other.getFixedPartitionAttributes()))) {
      // throw new RuntimeException("this="+this.toString() + "   other=" + other.toString());
      return false;
    }

    PartitionListener[] otherPListeners = other.getPartitionListeners();
    PartitionListener[] thisPListeners = this.getPartitionListeners();

    if (otherPListeners.length != thisPListeners.length) {
      return false;
    }
    Set<String> otherListenerClassName = new HashSet<String>();
    for (int i = 0; i < otherPListeners.length; i++) {
      PartitionListener listener = otherPListeners[i];
      otherListenerClassName.add(listener.getClass().getName());
    }
    Set<String> thisListenerClassName = new HashSet<String>();
    for (int i = 0; i < thisPListeners.length; i++) {
      PartitionListener listener = thisPListeners[i];
      thisListenerClassName.add(listener.getClass().getName());
    }
    if (!thisListenerClassName.equals(otherListenerClassName)) {
      return false;
    }

    return true;
  }