All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.gemstone.gemfire.pdx.internal.EnumInfo Maven / Gradle / Ivy

The newest version!
/*
 * Copyright (c) 2010-2015 Pivotal Software, Inc. 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. See accompanying
 * LICENSE file.
 */
package com.gemstone.gemfire.pdx.internal;

import java.io.DataInput;
import java.io.DataOutput;
import java.io.IOException;
import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

import com.gemstone.gemfire.DataSerializer;
import com.gemstone.gemfire.internal.ClassPathLoader;
import com.gemstone.gemfire.internal.DSCODE;
import com.gemstone.gemfire.internal.DataSerializableFixedID;
import com.gemstone.gemfire.internal.HeapDataOutputStream;
import com.gemstone.gemfire.internal.InternalDataSerializer;
import com.gemstone.gemfire.internal.Sendable;
import com.gemstone.gemfire.internal.i18n.LocalizedStrings;
import com.gemstone.gemfire.internal.shared.Version;
import com.gemstone.gemfire.pdx.PdxInstance;
import com.gemstone.gemfire.pdx.PdxSerializationException;
import com.gemstone.gemfire.pdx.WritablePdxInstance;

public class EnumInfo implements DataSerializableFixedID {
  private String clazz;
  private String name;
  // The ordinal field is only used to support comparison.
  // It is not used for equals or hashcode.
  private int ordinal;
  private transient volatile WeakReference> enumCache = null;
  
  public EnumInfo(Enum e) {
    this.clazz = e.getDeclaringClass().getName();
    this.name = e.name();
    this.ordinal = e.ordinal();
    this.enumCache = new WeakReference>(e);
  }
  
  public EnumInfo(String clazz, String name, int enumOrdinal) {
    this.clazz = clazz;
    this.name = name;
    this.ordinal = enumOrdinal;
  }

  public EnumInfo() {
  }

  public int getDSFID() {
    return ENUM_INFO;
  }

  public void toData(DataOutput out) throws IOException {
    DataSerializer.writeString(this.clazz, out);
    DataSerializer.writeString(this.name, out);
    DataSerializer.writePrimitiveInt(this.ordinal, out);
  }

  public void fromData(DataInput in) throws IOException, ClassNotFoundException {
    this.clazz = DataSerializer.readString(in);
    this.name = DataSerializer.readString(in);
    this.ordinal = DataSerializer.readPrimitiveInt(in);
  }

  public void flushCache() {
    synchronized (this) {
      this.enumCache = null;
    }
  }
  
  public Enum getEnum() throws ClassNotFoundException {
    Enum result;
    if (InternalDataSerializer.LOAD_CLASS_EACH_TIME) {
      result = loadEnum();
    } else {
      result = getExistingEnum();
      if (result == null) {
        synchronized (this) {
          result = getExistingEnum();
          if (result == null) {
            result = loadEnum();
            this.enumCache = new WeakReference>(result);
          }
        }
      }
    }
    return result;
  }
  public int getOrdinal() {
    return this.ordinal;
  }
  private Enum getExistingEnum() {
    WeakReference> wr = this.enumCache;
    if (wr != null) {
      return wr.get();
    }
    return null;
  }
  
  @SuppressWarnings("unchecked")
  private Enum loadEnum() throws ClassNotFoundException {
    @SuppressWarnings("rawtypes")
    Class c = InternalDataSerializer.getCachedClass(this.clazz);
    try {
      return Enum.valueOf(c, this.name);
    } catch (IllegalArgumentException ex) {
      throw new PdxSerializationException("PDX enum field could not be read because \"" + this.name + "\" is not a valid name in enum class " + c, ex);
    }
  }

  @Override
  public int hashCode() {
    final int prime = 31;
    int result = 1;
    result = prime * result + ((clazz == null) ? 0 : clazz.hashCode());
    result = prime * result + ((name == null) ? 0 : name.hashCode());
    return result;
  }

  @Override
  public String toString() {
    return clazz + "." + name;
  }

  @Override
  public boolean equals(Object obj) {
    if (this == obj)
      return true;
    if (obj == null)
      return false;
    if (getClass() != obj.getClass())
      return false;
    EnumInfo other = (EnumInfo) obj;
    if (clazz == null) {
      if (other.clazz != null)
        return false;
    } else if (!clazz.equals(other.clazz))
      return false;
    if (name == null) {
      if (other.name != null)
        return false;
    } else if (!name.equals(other.name))
      return false;
    if (this.ordinal != other.ordinal) {
      throw new PdxSerializationException("The ordinal value for the enum " + this.name + " on class " + this.clazz + " can not be changed. Pdx only allows new enum constants to be added to the end of the enum.");
    }
    return true;
  }

  public PdxInstance getPdxInstance(int enumId) {
    return new PdxInstanceEnumInfo(enumId, this);
  }

  public static class PdxInstanceEnumInfo implements PdxInstance, Sendable, ConvertableToBytes, ComparableEnum {
    private static final long serialVersionUID = 7907582104525106416L;
    private final int enumId;
    private final EnumInfo ei;

    public PdxInstanceEnumInfo(int enumId, EnumInfo ei) {
      this.enumId = enumId;
      this.ei = ei;
    }

    public String getClassName() {
      return this.ei.clazz;
    }
    public String getName() {
      return this.ei.name;
    }
    public int getOrdinal() {
      return this.ei.ordinal;
    }

    public boolean isEnum() {
      return true;
    }

    public Object getObject() {
      try {
        return this.ei.getEnum();
      } catch (ClassNotFoundException ex) {
        throw new PdxSerializationException(
            LocalizedStrings.DataSerializer_COULD_NOT_CREATE_AN_INSTANCE_OF_A_CLASS_0
            .toLocalizedString(getClassName()), ex);
      }
    }

    public boolean hasField(String fieldName) {
      return getFieldNames().contains(fieldName);
    }

    static private final List fieldNames;
    static {
      ArrayList tmp = new ArrayList(2);
      tmp.add("name");
      tmp.add("ordinal");
      fieldNames = Collections.unmodifiableList(tmp);
    }
    
    public List getFieldNames() {
      return fieldNames;
    }

    public boolean isIdentityField(String fieldName) {
      return false;
    }

    public Object getField(String fieldName) {
      if ("name".equals(fieldName)) {
        return getName();
      } else if ("ordinal".equals(fieldName)) {
        return getOrdinal();
      }
      return null;
    }

    public WritablePdxInstance createWriter() {
      throw new IllegalStateException("PdxInstances that are an enum can not be modified.");
    }

    public void sendTo(DataOutput out) throws IOException {
      InternalDataSerializer.writePdxEnumId(this.enumId, out);
    }
    
    @Override
    public int hashCode() {
      // this hashCode needs to be kept consistent with PdxInstanceEnum
      final int prime = 31;
      int result = 1;
      String className = getClassName();
      String enumName = getName();
      result = prime * result + ((className == null) ? 0 : className.hashCode());
      result = prime * result + ((enumName == null) ? 0 : enumName.hashCode());
      return result;
    }

    @Override
    public boolean equals(Object obj) {
      if (this == obj)
        return true;
      if (obj == null)
        return false;
      if (!(obj instanceof ComparableEnum))
        return false;
      ComparableEnum other = (ComparableEnum) obj;
      String className = getClassName();
      if (className == null) {
        if (other.getClassName() != null)
          return false;
      } else if (!className.equals(other.getClassName()))
        return false;
      String enumName = getName();
      if (enumName == null) {
        if (other.getName() != null)
          return false;
      } else if (!enumName.equals(other.getName()))
        return false;
      return true;
    }
    
    @Override
    public String toString() {
      return this.ei.name;
    }

    public byte[] toBytes() throws IOException {
      HeapDataOutputStream hdos = new HeapDataOutputStream(16, Version.CURRENT);
      sendTo(hdos);
      return hdos.toByteArray();
    }

    public int compareTo(Object o) {
      if (o instanceof ComparableEnum) {
        ComparableEnum other = (ComparableEnum)o;
        if (!getClassName().equals(other.getClassName())) {
          throw new ClassCastException("Can not compare a " + getClassName() + " to a " + other.getClassName());
        }
        return getOrdinal() - other.getOrdinal();
      } else {
        throw new ClassCastException("Can not compare an instance of " + o.getClass() + " to a " + this.getClass());
      }
    }
  }

  @Override
  public Version[] getSerializationVersions() {
    return null;
  }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy