blob: 5b33a87f7047f25ea94069cc3c692c76954fd1bd [file] [log] [blame]
package org.apache.helix;
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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.
*/
import java.lang.reflect.Constructor;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.I0Itec.zkclient.serialize.ZkSerializer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.apache.helix.api.exceptions.HelixMetaDataAccessException;
/**
* A wrapper class for ZNRecord. Used as a base class for IdealState, CurrentState, etc.
*/
public class HelixProperty {
private static Logger LOG = LoggerFactory.getLogger(HelixProperty.class);
public enum HelixPropertyAttribute {
BUCKET_SIZE,
BATCH_MESSAGE_MODE
}
protected final ZNRecord _record;
/**
* Metadata of a HelixProperty
*/
public static class Stat {
// the version field of zookeeper Stat
private int _version;
private long _creationTime;
private long _modifiedTime;
private long _ephemeralOwner;
public Stat(int version, long creationTime, long modifiedTime, long ephemeralOwner) {
_version = version;
_creationTime = creationTime;
_modifiedTime = modifiedTime;
_ephemeralOwner = ephemeralOwner;
}
public Stat(Stat stat) {
_version = stat.getVersion();
_creationTime = stat.getCreationTime();
_modifiedTime = stat.getModifiedTime();
_ephemeralOwner = stat.getEphemeralOwner();
}
public Stat() {
_version = -1;
_creationTime = -1;
_modifiedTime = -1;
_ephemeralOwner = -1;
}
public int getVersion() {
return _version;
}
public void setVersion(int version) {
_version = version;
}
public long getCreationTime() {
return _creationTime;
}
public void setCreationTime(long creationTime) {
_creationTime = creationTime;
}
public long getModifiedTime() {
return _modifiedTime;
}
public void setModifiedTime(long modifiedTime) {
_modifiedTime = modifiedTime;
}
public long getEphemeralOwner() {
return _ephemeralOwner;
}
public void setEphemeralOwner(long ephemeralOwner) {
_ephemeralOwner = ephemeralOwner;
}
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (!(o instanceof Stat)) {
return false;
}
Stat stat = (Stat) o;
if (_ephemeralOwner != stat._ephemeralOwner) {
return false;
}
if (_version != stat._version) {
return false;
}
if (_creationTime != stat._creationTime) {
return false;
}
return _modifiedTime == stat._modifiedTime;
}
@Override
public int hashCode() {
int result = _version;
result = 31 * result + (int) (_creationTime ^ (_creationTime >>> 32));
result = 31 * result + (int) (_modifiedTime ^ (_modifiedTime >>> 32));
result = 31 * result + (int) (_ephemeralOwner ^ (_ephemeralOwner >>> 32));
return result;
}
@Override
public String toString() {
return "Stat {" + "_version=" + _version + ", _creationTime=" + _creationTime
+ ", _modifiedTime=" + _modifiedTime + ", _ephemeralOwner=" + _ephemeralOwner + '}';
}
}
private Stat _stat;
/**
* Initialize the property with an identifier
* @param id
*/
public HelixProperty(String id) {
this(new ZNRecord(id), id);
}
/**
* Initialize the property with an existing ZNRecord
* @param record
*/
public HelixProperty(ZNRecord record) {
this(record, record.getId());
}
/**
* Initialize the property with an existing ZNRecord with new record id
* @param record
* @param id
*/
public HelixProperty(ZNRecord record, String id) {
_record = new ZNRecord(record, id);
_stat = new Stat(_record.getVersion(), _record.getCreationTime(), _record.getModifiedTime(), _record.getEphemeralOwner());
}
/**
* Get the property identifier
* @return the property id
*/
public final String getId() {
return _record.getId();
}
/**
* Get the backing ZNRecord
* @return ZNRecord object associated with this property
*/
public final ZNRecord getRecord() {
return _record;
}
/**
* Set the changes to the backing ZNRecord
* @param deltaList list of ZNRecord updates to be made
*/
public final void setDeltaList(List<ZNRecordDelta> deltaList) {
_record.setDeltaList(deltaList);
}
@Override
public String toString() {
return "ZnRecord=" + _record.toString() + ", Stat=" + _stat.toString() ;
}
/**
* Get the size of buckets defined
* @return the bucket size, or 0 if not defined
*/
public int getBucketSize() {
String bucketSizeStr = _record.getSimpleField(HelixPropertyAttribute.BUCKET_SIZE.toString());
int bucketSize = 0;
if (bucketSizeStr != null) {
try {
bucketSize = Integer.parseInt(bucketSizeStr);
} catch (NumberFormatException e) {
// OK
}
}
return bucketSize;
}
/**
* Set the size of buckets defined
* @param bucketSize the bucket size (will default to 0 if negative)
*/
public void setBucketSize(int bucketSize) {
if (bucketSize <= 0)
bucketSize = 0;
_record.setSimpleField(HelixPropertyAttribute.BUCKET_SIZE.toString(), "" + bucketSize);
}
/**
* static method that converts ZNRecord to an instance that subclasses HelixProperty
* @param clazz subclass of HelixProperty
* @param record the ZNRecord describing the property
* @return typed instance corresponding to the record, or null if conversion fails
*/
public static <T extends HelixProperty> T convertToTypedInstance(Class<T> clazz, ZNRecord record) {
if (record == null) {
return null;
}
try {
Constructor<T> constructor = clazz.getConstructor(ZNRecord.class);
return constructor.newInstance(record);
} catch (Exception e) {
LOG.error("Exception convert znrecord: " + record + " to class: " + clazz, e);
}
return null;
}
/**
* Convert a collection of records to typed properties
* @param clazz Subclass of HelixProperty
* @param records the ZNRecords describing the property
* @return list of typed instances for which the conversion succeeded, or null if records is null
*/
public static <T extends HelixProperty> List<T> convertToTypedList(Class<T> clazz,
Collection<ZNRecord> records) {
if (records == null) {
return null;
}
List<T> decorators = new ArrayList<T>();
for (ZNRecord record : records) {
T decorator = HelixProperty.convertToTypedInstance(clazz, record);
if (decorator != null) {
decorators.add(decorator);
}
}
return decorators;
}
/**
* Converts a list of records to a map of the record identifier to typed properties
* @param records the ZNRecords to convert
* @return id --> HelixProperty subclass map
*/
public static <T extends HelixProperty> Map<String, T> convertListToMap(List<T> records) {
if (records == null) {
return Collections.emptyMap();
}
Map<String, T> decorators = new HashMap<String, T>();
for (T record : records) {
decorators.put(record.getId(), record);
}
return decorators;
}
/**
* Convert typed properties to a list of records
* @param typedInstances objects subclassing HelixProperty
* @return a list of ZNRecord objects
*/
public static <T extends HelixProperty> List<ZNRecord> convertToList(List<T> typedInstances) {
if (typedInstances == null) {
return Collections.emptyList();
}
List<ZNRecord> records = new ArrayList<ZNRecord>();
for (T typedInstance : typedInstances) {
records.add(typedInstance.getRecord());
}
return records;
}
/**
* Change the state of batch messaging
* @param enable true to enable, false to disable
*/
public void setBatchMessageMode(boolean enable) {
_record.setSimpleField(HelixPropertyAttribute.BATCH_MESSAGE_MODE.toString(), "" + enable);
}
/**
* Get the state of batch messaging
* @return true if enabled, false if disabled
*/
public boolean getBatchMessageMode() {
String enableStr = _record.getSimpleField(HelixPropertyAttribute.BATCH_MESSAGE_MODE.toString());
if (enableStr == null) {
return false;
}
try {
return Boolean.parseBoolean(enableStr.toLowerCase());
} catch (Exception e) {
return false;
}
}
/**
* Get the metadata (stat) of this record
* @return HelixProperty.Stat
*/
public Stat getStat() {
return _stat;
}
/**
* Set the metadata (stat) for this record
* @param stat
*/
public void setStat(Stat stat) {
_stat = new Stat(stat);
}
/**
* Get property validity
* @return true if valid, false if invalid
*/
public boolean isValid() {
return true;
}
public byte[] serialize(ZkSerializer serializer) {
return serializer.serialize(_record);
}
@Override
public boolean equals(Object obj) {
if (obj == null) {
return false;
}
if (obj instanceof HelixProperty) {
HelixProperty that = (HelixProperty) obj;
if (that.getRecord() != null) {
return that.getRecord().equals(this.getRecord());
}
}
return false;
}
}