/*
* Copyright (c) 2002-2012 Alibaba Group Holding Limited.
* 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 com.alibaba.toolkit.util.enumeration;
import java.io.Serializable;
import java.text.MessageFormat;
import java.util.Iterator;
import com.alibaba.toolkit.util.typeconvert.ConvertChain;
import com.alibaba.toolkit.util.typeconvert.Converter;
import com.alibaba.toolkit.util.typeconvert.Convertible;
/**
* 代表一个或多个<code>Flags</code>构成的位集.
*
* @author Michael Zhou
* @version $Id: FlagSet.java,v 1.1 2003/07/03 07:26:20 baobao Exp $
*/
public abstract class FlagSet implements Flags, Cloneable, Comparable, Serializable, Convertible {
private static final long serialVersionUID = -5507969553098965333L;
private final Class enumClass;
protected transient boolean immutable;
/**
* 创建一个位集.
*
* @param enumClass 位集所代表的内部枚举类
*/
public FlagSet(Class enumClass) {
this.enumClass = enumClass;
if (!Enum.class.isAssignableFrom(enumClass)) {
throw new IllegalArgumentException(MessageFormat.format(EnumConstants.ILLEGAL_CLASS, new Object[] {
enumClass.getName(), Enum.class.getName() }));
}
if (!Flags.class.isAssignableFrom(enumClass)) {
throw new IllegalArgumentException(MessageFormat.format(EnumConstants.ILLEGAL_INTERFACE, new Object[] {
enumClass.getName(), Flags.class.getName() }));
}
}
/**
* 取得内部枚举类型.
*
* @return 内部枚举类型
*/
public Class getEnumClass() {
return enumClass;
}
/**
* 取得位集的值的类型.
*
* @return 位集的值的类型
*/
public Class getUnderlyingClass() {
return Enum.getUnderlyingClass(enumClass);
}
/**
* 设置位集的值, 值的类型由<code>getUnderlyingClass()</code>确定.
*
* @param value 位集的值
*/
public abstract void setValue(Object value);
/**
* 取得位集的值, 值的类型由<code>getUnderlyingClass()</code>确定.
*
* @return 位集的值
*/
public abstract Object getValue();
/**
* 实现<code>Number</code>类, 取得<code>byte</code>值.
*
* @return <code>byte</code>值
*/
public byte byteValue() {
return (byte) intValue();
}
/**
* 实现<code>Number</code>类, 取得<code>short</code>值.
*
* @return <code>short</code>值
*/
public short shortValue() {
return (short) intValue();
}
/**
* 实现<code>Convertible</code>接口, 取得将当前位集转换成指定<code>targetType</code>的
* <code>Converter</code>. 转换的规则如下:
* <ul>
* <li>如果<code>targetType</code>是字符串, 则返回<code>FlagSet.toString()</code>.</li>
* <li>否则将位集的值传递到转换链中.</li>
* </ul>
*
* @param targetType 目标类型
* @return 将当前位集转换成指定<code>targetType</code>的<code>Converter</code>
*/
public Converter getConverter(Class targetType) {
return new Converter() {
public Object convert(Object value, ConvertChain chain) {
FlagSet flagSet = (FlagSet) value;
Class targetType = chain.getTargetType();
if (String.class.equals(targetType)) {
return flagSet.toString();
}
return chain.convert(flagSet.getValue());
}
};
}
/**
* 复制位集对象.
*
* @return 复制品
*/
@Override
public Object clone() {
FlagSet flagSet = null;
try {
flagSet = (FlagSet) super.clone();
} catch (CloneNotSupportedException e) {
throw new InternalError(MessageFormat.format(EnumConstants.CLONE_NOT_SUPPORTED, new Object[] { getClass()
.getName() }));
}
flagSet.immutable = false;
return flagSet;
}
/**
* 和另一个位集比较大小, 就是按位集的值比较.
*
* @param other 要比较的位集
* @return 如果等于<code>0</code>, 表示值相等, 大于<code>0</code>表示当前的位集的值比
* <code>otherFlags</code>大, 小于<code>0</code>表示当前的位集的值比
* <code>otherFlags</code>小
*/
public int compareTo(Object other) {
if (!getClass().equals(other.getClass())) {
throw new IllegalArgumentException(MessageFormat.format(EnumConstants.COMPARE_TYPE_MISMATCH, new Object[] {
getClass().getName(), other.getClass().getName() }));
}
FlagSet otherFlagSet = (FlagSet) other;
if (!enumClass.equals(otherFlagSet.enumClass)) {
throw new IllegalArgumentException(MessageFormat.format(EnumConstants.COMPARE_UNDERLYING_CLASS_MISMATCH,
new Object[] { enumClass.getName(), otherFlagSet.enumClass.getName() }));
}
return ((Comparable) getValue()).compareTo(otherFlagSet.getValue());
}
/**
* 比较两个位集是否相等, 即: 类型相同, 内部类相同, 并且值相同.
*
* @param obj 要比较的对象
* @return 如果相等, 则返回<code>true</code>
*/
@Override
public boolean equals(Object obj) {
if (obj == this) {
return true;
}
if (obj == null || !getClass().equals(obj.getClass()) || !enumClass.equals(((FlagSet) obj).enumClass)) {
return false;
}
return getValue().equals(((FlagSet) obj).getValue());
}
/**
* 取得位集的hash值. 如果两个位集相同, 则它们的hash值一定相同.
*
* @return hash值
*/
@Override
public int hashCode() {
return getClass().hashCode() ^ enumClass.hashCode() ^ getValue().hashCode();
}
/**
* 取得位集的字符串表示.
*
* @return 位集的字符串表示
*/
@Override
public String toString() {
StringBuffer buffer = new StringBuffer("{");
String sep = "";
for (Iterator i = Enum.iterator(enumClass); i.hasNext(); ) {
Flags flags = (Flags) i.next();
if (test(flags)) {
buffer.append(sep);
sep = ", ";
buffer.append(flags);
}
}
buffer.append("}");
return buffer.toString();
}
/**
* 设置成不可变的位集.
*
* @return 位集本身
*/
public Flags setImmutable() {
this.immutable = true;
return this;
}
/**
* 清除当前位集的全部位.
*
* @return 当前位集
*/
public abstract Flags clear();
/**
* 清除当前位集的指定位, 等效于<code>andNot</code>操作.
*
* @param flags 标志位
* @return 当前位集
*/
public Flags clear(Flags flags) {
checkImmutable();
return andNot(flags);
}
/**
* 设置当前位集的指定位, 等效于<code>or</code>操作.
*
* @param flags 标志位
* @return 当前位集
*/
public Flags set(Flags flags) {
checkImmutable();
return or(flags);
}
/**
* 测试当前位集的指定位, 等效于<code>and(flags) != 0</code>.
*
* @param flags 标志位
* @return 如果指定位被置位, 则返回<code>true</code>
*/
public abstract boolean test(Flags flags);
/**
* 如果是不可变位集, 则创建一个新的位集, 否则返回本身.
*
* @return 位集本身或复制品
*/
protected FlagSet getFlagSetForModification() {
if (immutable) {
return (FlagSet) this.clone();
} else {
return this;
}
}
/** 如果是不可变的位集, 则掷出<code>UnsupportedOperationException</code>. */
protected void checkImmutable() {
if (immutable) {
throw new UnsupportedOperationException(EnumConstants.FLAG_SET_IS_IMMUTABLE);
}
}
/**
* 确保<code>flags</code>非空, 并且是<code>Enum</code>或<code>FlagSet</code>类.
*
* @param flags 要判断的对象
*/
protected void checkFlags(Flags flags) {
if (flags == null) {
throw new NullPointerException(EnumConstants.FLAGS_IS_NULL);
}
Class flagsClass = flags.getClass();
if (!enumClass.equals(flagsClass) && !getClass().equals(flagsClass)) {
throw new IllegalArgumentException(MessageFormat.format(EnumConstants.ILLEGAL_FLAGS_OBJECT, new Object[] {
enumClass.getName(), getClass().getName() }));
}
}
}