001    /*
002     * To change this template, choose Tools | Templates
003     * and open the template in the editor.
004     */
005    package com.nativelibs4java.util;
006    
007    import java.util.*;
008    
009    /**
010     * Methods to ease conversion between EnumValue-annotated enums and their integer value.
011     * @author ochafik
012     */
013    public class EnumValues {
014    
015        private static class Cache<E extends Enum<?>> {
016    
017            final Map<Long, E> enumsByValue = new LinkedHashMap<Long, E>();
018            final Map<E, Long> valuesByEnum = new LinkedHashMap<E, Long>();
019    
020            public Cache(Class<E> enumClass) {
021    
022                if (ValuedEnum.class.isAssignableFrom(enumClass)) {
023                    for (E e : enumClass.getEnumConstants()) {
024                        long value = ((ValuedEnum)e).value();
025                        enumsByValue.put(value, e);
026                        valuesByEnum.put(e, value);
027                    }
028                } else {
029                    for (E e : enumClass.getEnumConstants()) {
030                        EnumValue ev = null;
031                        try {
032                            ev = enumClass.getField(e.name()).getAnnotation(EnumValue.class);
033                        } catch (Exception ex) {
034                            throw new RuntimeException(ex);
035                        }
036                        if (ev == null) {
037                            throw new IllegalArgumentException("Enum value is not annotated with the " + EnumValue.class.getName() + " annotation : " + e);
038                        }
039                        long value = ev.value();
040                        enumsByValue.put(value, e);
041                        valuesByEnum.put(e, value);
042                    }
043                }
044            }
045        }
046        private static final Map<Class<? extends Enum<?>>, Cache<?>> caches = new HashMap<Class<? extends Enum<?>>, Cache<?>>();
047    
048        @SuppressWarnings("unchecked")
049        private static synchronized <E extends Enum<?>> Cache<E> getCache(Class<E> enumClass) {
050            Cache<E> cache = (Cache<E>) caches.get(enumClass);
051            if (cache == null) {
052                caches.put(enumClass, cache = new Cache(enumClass));
053            }
054            return cache;
055        }
056    
057        /**
058         * Get the first enum item in enum class E which EnumValue value is equal to value
059         * @param <E> type of the enum
060         * @param value
061         * @param enumClass
062         * @return first enum item with matching value, null if there is no matching enum item
063         */
064        public static <E extends Enum<E>> E getEnum(long value, Class<E> enumClass) {
065            return getCache(enumClass).enumsByValue.get(value);
066        }
067    
068        /**
069         * Get the set of all the enum item in enum class E which EnumValue value flags are all present in value
070         * @param <E> type of the enum
071         * @param value
072         * @param enumClass
073         * @return enum items with matching value flags
074         */
075        public static <E extends Enum<E>> EnumSet<E> getEnumSet(long value, Class<E> enumClass) {
076            EnumSet<E> set = EnumSet.noneOf(enumClass);
077            for (Map.Entry<Long, E> pair : getCache(enumClass).enumsByValue.entrySet()) {
078                long ev = pair.getKey();
079                if ((ev & value) == ev) {
080                    set.add(pair.getValue());
081                }
082            }
083            return set;
084        }
085    
086        /**
087         * Get the integer value associated with an enum item
088         * @see EnumValue
089         * @param enumItem
090         * @return the numeric value of the enum
091         */
092        @SuppressWarnings("unchecked")
093        public static <E extends Enum<?>> long getValue(E enumItem) {
094            return getCache((Class<E>) enumItem.getDeclaringClass()).valuesByEnum.get(enumItem);
095        }
096    
097        /**
098         * Get the integer value resulting from ORing all the values of all the enum items present in the enum set.
099         * @see EnumValues#getValue(java.lang.Enum)
100         * @see EnumValue
101         * @param set the EnumSet to process
102         * @return the OR of all the values of the enums in the set
103         */
104        public static <E extends Enum<E>> long getValue(EnumSet<E> set) {
105            long v = 0;
106            for (E e : set) {
107                v |= getValue(e);
108            }
109            return v;
110        }
111    }