/* * NOTE: This copyright does *not* cover user programs that use HQ * program services by normal system calls through the application * program interfaces provided as part of the Hyperic Plug-in Development * Kit or the Hyperic Client Development Kit - this is merely considered * normal use of the program, and does *not* fall under the heading of * "derived work". * * Copyright (C) [2004, 2005, 2006], Hyperic, Inc. * This file is part of HQ. * * HQ is free software; you can redistribute it and/or modify * it under the terms version 2 of the GNU General Public License as * published by the Free Software Foundation. This program is distributed * in the hope that it will be useful, but WITHOUT ANY WARRANTY; without * even the implied warranty of MERCHANTABILITY or FITNESS FOR A * PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 * USA. */ package org.hyperic.util; import java.io.ObjectStreamException; import java.io.Serializable; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.ResourceBundle; import java.util.Set; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; /** * Utility class for typesafe enums. People implementing such enums should * subclass this class. * * Enums have a code and a description. The code must be unique for enums * of a specific class. This has great use in things like Web-UI where you * need a code representation as well as a string (rendering a listbox) * * Each enumeration also provides a resource bundle and locale property to * look up the 'value' of the enumeration in that bundle. * * This class can also be used as a dynamic enumeration as long as all the * enumerations use a unique code. * * XXX: It would be good to implement the PersistentEnum stylee via * a UserType in Hibernate, so we don't have to do the conversion in * every class that uses an enum. Don't have the time now.. :-( * http://www.hibernate.org/203.html */ public abstract class HypericEnum implements Serializable { private static final Log _log = LogFactory.getLog(HypericEnum.class); private static final boolean DEBUG_ENUMS = false; /** * Hash of classes onto sets of instances. * TODO: Change the sets into hashmaps so we can do quicker lookups. */ private static final Map _enumsByClass = new HashMap(); private Class _implClass; private int _code; private transient String _desc; private transient String _localeProp; private transient ResourceBundle _bundle; protected HypericEnum(int code, String desc, String localeProp, ResourceBundle bundle) { init(getClass(), code, desc, localeProp, bundle); } protected HypericEnum(Class c, int code, String desc, String localeProp, ResourceBundle bundle) { init(c, code, desc, localeProp, bundle); } private void init(Class c, int code, String desc, String localeProp, ResourceBundle bundle) { _implClass = c; _code = code; _desc = desc; _localeProp = localeProp; _bundle = bundle; if (_bundle == null) { _log.warn("Unable to find bundle when creating enum for [" + _implClass + "]"); } if (DEBUG_ENUMS) { if (_bundle != null && _bundle.getString(_localeProp) == null) { _log.warn("Unable to find prop [" + _localeProp + "] in " + "bundle [" + _bundle + "]"); } _log.info("[" + _bundle + "] (" + _localeProp + ") == " + getValue()); } synchronized (_enumsByClass) { Set vals = (Set)_enumsByClass.get(_implClass); if (vals == null) { vals = new HashSet(); _enumsByClass.put(_implClass, vals); } vals.add(this); } } protected final void unregister() { synchronized (_enumsByClass) { final Set vals = (Set)_enumsByClass.get(this._implClass); //vals must exist at this point vals.remove(this) ; }//EO synchronized block }//EOM public int getCode() { return _code; } /** * Returns the localized value of this enumeration. */ public String getValue() { String res; if (_bundle == null) { return "** No bundle for class " + _implClass + " **"; } res = _bundle.getString(_localeProp); if (res == null) { return "** Property [" + _localeProp + "] not found in bundle [" + _bundle.toString() + "]"; } return res; } public String getDescription() { return _desc; } @Override public String toString() { return _desc; } private static Comparator CODE_COMPARATOR = new Comparator() { public int compare(Object o1, Object o2) { HypericEnum e1, e2; e1 = (HypericEnum)o1; e2 = (HypericEnum)o2; if (e1.getCode() < e2.getCode()) return -1; else if(e1.getCode() == e2.getCode()) return 0; return 1; } }; /** * Like {@link #findByCode(Class, int)} except returns null instead of * throwing an exception */ public static HypericEnum getByCode(Class c, int code) { synchronized (_enumsByClass) { Set vals = (Set)_enumsByClass.get(c); if (vals != null) { for (Iterator i=vals.iterator(); i.hasNext(); ) { HypericEnum e = (HypericEnum)i.next(); if (e.getCode() == code) return e; } } } return null; } /** * Find an enum of a specific class type by code. * * @param c A subclass of {@link HypericEnum} * @param code The integer code represented by the enum * @return the enum, else null */ public static HypericEnum findByCode(Class c, int code) { HypericEnum res = getByCode(c, code); if (res != null) return res; throw new IllegalStateException("Unknown Enum Class [" + c.getName() + "] code=" + code); } /** * Find an enum of a specific class type by description. * * @param c A subclass of {@link HypericEnum} * @param description The description represented by the enum. * @return The enum, else null. */ public static HypericEnum findByDescription(Class c, String description) { synchronized (_enumsByClass) { Set vals = (Set)_enumsByClass.get(c); if (vals != null) { for (Iterator i = vals.iterator(); i.hasNext(); ) { HypericEnum e = (HypericEnum)i.next(); if (e.getDescription().equals(description)) { return e; } } } } return null; } /** * Return a list of {@link HypericEnum} objects for a specific class, * sorted by their code. * @param c Class to find enums for */ public static <T> List<T> getAll(Class<T> c) { List res; Set vals; synchronized (_enumsByClass) { vals = (Set)_enumsByClass.get(c); } if (vals == null) return Collections.EMPTY_LIST; res = new ArrayList(vals); Collections.sort(res, CODE_COMPARATOR); return Collections.unmodifiableList(res); } private Object readResolve() throws ObjectStreamException { return findByCode(_implClass, _code); } }