//----------------------------------------------------------------------------//
// //
// C o n s t a n t S e t //
// //
//----------------------------------------------------------------------------//
// <editor-fold defaultstate="collapsed" desc="hdr"> //
// Copyright © Hervé Bitteur and others 2000-2013. All rights reserved. //
// This software is released under the GNU General Public License. //
// Goto http://kenai.com/projects/audiveris to report bugs or suggestions. //
//----------------------------------------------------------------------------//
// </editor-fold>
package omr.constant;
import net.jcip.annotations.ThreadSafe;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.lang.reflect.Field;
import java.util.Collections;
import java.util.SortedMap;
import java.util.TreeMap;
/**
* This abstract class handles a set of Constants as a whole. In particular,
* this allows a user interface (such as {@link UnitTreeTable}) to present an
* editing table of the whole set of constants.
*
* <p>We recommend to define only one such static ConstantSet per class/unit as
* a subclass of this (abstract) ConstantSet. </p>
*
* @author Hervé Bitteur
*/
@ThreadSafe
public abstract class ConstantSet
{
//~ Static fields/initializers ---------------------------------------------
/** Usual logger utility */
private static final Logger logger = LoggerFactory.getLogger(ConstantSet.class);
//~ Instance fields --------------------------------------------------------
/** Name of the containing unit/class */
private final String unit;
/**
* The mapping between constant name & constant object. We use a sorted map
* to allow access by constant index in constant set, as required by
* ConstantTreeTable. This instance can only be lazily constructed, thanks
* to {@link #getMap} method, since all the enclosed constants must have
* been constructed beforehand.
*/
private volatile SortedMap<String, Constant> map;
//~ Constructors -----------------------------------------------------------
//-------------//
// ConstantSet //
//-------------//
/**
* A new ConstantSet instance is created, and registered at the UnitManager
* singleton, but its map of internal constants will need to be built later.
*/
public ConstantSet ()
{
unit = getClass().getDeclaringClass().getName();
// System.out.println(
// "\n" + Thread.currentThread().getName() +
// ": Creating ConstantSet " + unit);
// Register this instance
UnitManager.getInstance().addSet(this);
}
//~ Methods ----------------------------------------------------------------
//--------//
// dumpOf //
//--------//
/**
* A utility method to dump current value of each constant in the set.
*
* @return the string representation of this set
*/
public String dumpOf ()
{
StringBuilder sb = new StringBuilder();
sb.append(String.format("[%s]%n", unit));
for (Constant constant : getMap().values()) {
String origin = constant.getValueOrigin();
if (origin.equals("SRC")) {
origin = "";
} else {
origin = "[" + origin + "]";
}
sb.append(String.format(
"%-25s %12s %-14s =%5s %-25s\t%s%n",
constant.getName(),
constant.getShortTypeName(),
(constant.getQuantityUnit() != null)
? ("(" + constant.getQuantityUnit() + ")") : "",
origin,
constant.getCurrentString(),
constant.getDescription()));
}
return sb.toString();
}
//-------------//
// getConstant //
//-------------//
/**
* Report a constant knowing its name in the constant set
*
* @param name the desired name
*
* @return the proper constant, or null if not found
*/
public Constant getConstant (String name)
{
return getMap().get(name);
}
//-------------//
// getConstant //
//-------------//
/**
* Report a constant knowing its index in the constant set
*
* @param i the desired index value
*
* @return the proper constant
*/
public Constant getConstant (int i)
{
return Collections.list(Collections.enumeration(getMap().values())).get(
i);
}
//---------//
// getName //
//---------//
/**
* Report the name of the enclosing unit
*
* @return unit name
*/
public String getName ()
{
return unit;
}
//------------//
// initialize //
//------------//
/**
* Make sure this ConstantSet has properly been initialized (its map of
* constants has been built)
*
* @return true if initialized correctly, false otherwise
*/
public boolean initialize ()
{
return getMap() != null;
}
//------------//
// isModified //
//------------//
/**
* Predicate to check whether at least one of the constant of the set has
* been modified
*
* @return the modification status of the whole set
*/
public boolean isModified ()
{
for (Constant constant : getMap().values()) {
if (constant.isModified()) {
return true;
}
}
return false;
}
//------//
// size //
//------//
/**
* Report the number of constants in this constant set
*
* @return the size of the constant set
*/
public int size ()
{
return getMap().size();
}
//----------//
// toString //
//----------//
/**
* Return the last part of the ConstantSet name, without the leading package
* names. This short name is used by Constant TreeTable
*
* @return just the (unqualified) name of the ConstantSet
*/
@Override
public String toString ()
{
StringBuilder sb = new StringBuilder();
//sb.append("<html><b>");
int dot = unit.lastIndexOf('.');
if (dot != -1) {
sb.append(unit.substring(dot + 1));
} else {
sb.append(unit);
}
//sb.append("</b></html>");
return sb.toString();
}
//--------//
// getMap //
//--------//
private SortedMap<String, Constant> getMap ()
{
if (map == null) {
// Initialize map content
initMap();
}
return map;
}
//---------//
// initMap //
//---------//
/**
* Now that the enclosed constants of this set have been constructed, let
* assign them their unit and name parameters.
*/
private void initMap ()
{
SortedMap<String, Constant> tempMap = new TreeMap<>();
// Retrieve values of all fields
Class<?> cl = getClass();
try {
for (Field field : cl.getDeclaredFields()) {
field.setAccessible(true);
String name = field.getName();
// Make sure that we have only Constants in this ConstantSet
Object obj = field.get(this);
// Not yet allocated, no big deal, we'll get back to it later
if (obj == null) {
///logger.warn("ConstantSet not fully allocated yet");
return;
}
if (obj instanceof Constant) {
Constant constant = (Constant) obj;
constant.setUnitAndName(unit, name);
tempMap.put(name, constant);
} else {
logger.error(
"ConstantSet in unit ''{}'' contains a non"
+ " Constant field ''{}'' obj= {}",
unit, name, obj);
}
}
// Assign the constructed map atomically
map = tempMap;
} catch (SecurityException | IllegalArgumentException |
IllegalAccessException ex) {
logger.warn("Error initializing map of ConstantSet " + this, ex);
}
}
}