/** * '$RCSfile: PropertiesMetaData.java,v $' * Copyright: 2008 Regents of the University of California * * '$Author: daigle $' * '$Date: 2009-01-20 18:16:29 $' * '$Revision: 1.8 $' * * Permission is hereby granted, without written agreement and without * license or royalty fees, to use, copy, modify, and distribute this * software and its documentation for any purpose, provided that the above * copyright notice and the following two paragraphs appear in all copies * of this software. * * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY * FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF * THE UNIVERSITY OF CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES, * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE * PROVIDED HEREUNDER IS ON AN "AS IS" BASIS, AND THE UNIVERSITY OF * CALIFORNIA HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, * ENHANCEMENTS, OR MODIFICATIONS.USA */ package edu.ucsb.nceas.utilities; import java.io.File; import java.io.IOException; import java.util.Map; import java.util.Set; import java.util.SortedMap; import java.util.TreeMap; import java.util.Vector; import javax.xml.transform.TransformerException; /** * Encapsulate the meta-informaiton about Options so that this information can * be used by applications for managing options in a usable way. The metadata * managed for each option includes a human-readable label, a description of * the option, an index into the order of the option relative to others in its * group, and a category (group) for the option. This information is stored in a * file which can be accessed using the load() and store() methods. * * @author Matt Jones */ public class PropertiesMetaData { /** * A hash containing the metadata for each option, indexed by the key * used to store the option. Values are instances of the Metadata inner * class. */ private TreeMap propertyMap; private TreeMap groupMap; /** * Construct a new instance of the optionsMap class. * @param xmlPropsFile the file object containing the metadata to be loaded (XML format) */ public PropertiesMetaData(String propFileName) throws IOException, TransformerException { File xmlPropsFile = new File(propFileName); propertyMap = new TreeMap(); groupMap = new TreeMap(); XMLProperties metadataProperties = new XMLProperties(); metadataProperties.load(xmlPropsFile); // Load the metadata from the file load(metadataProperties); } /** * Insert or update a metadata entry for a given key. * * @param key the key of the property to be updated * @param label a human-readable lable for the property * @param group the human-readable group for the property * @param index the within-group index in which the property should be displayed * @param description a human-readable description of the property */ public synchronized void setMetadata(String key, String label, int groupId, int index, String description, String helpFile) { MetaDataProperty metaData = (MetaDataProperty)propertyMap.get(key); if (metaData == null) { metaData = new MetaDataProperty(key, label, groupId, index, description, helpFile); } else { metaData.setKey(key); metaData.setLabel(label); metaData.setGroupId(groupId); metaData.setIndex(index); metaData.setDescription(description); metaData.setHelpFile(helpFile); } propertyMap.put(key, metaData); } /** * Get a Set of the groups that are common across all of the properties. * @return Set of the groups found for all properties */ public synchronized MetaDataGroup getGroup(int groupId) { return getGroups().get(new Integer(groupId)); } /** * Get a Map of the groups that are common across all of the properties. * @return Set of the groups found for all properties */ public synchronized Map getGroups() { return groupMap; } /** * Get a Map of all properties metadata * * @return a Map of properties metadata */ public synchronized Map getProperties() { return propertyMap; } /** * Get a Set of all keys in the properties * @return Set of all keys in the properties */ public synchronized Set getKeys() { return propertyMap.keySet(); } /** * Get a Set of the keys for properties that are members of a given group. * * @param target * the target group to be searched for matching keys * @return Set of the keys found within the given group */ public synchronized SortedMap getPropertiesInGroup( int groupId) { TreeMap groupPropertyMap = new TreeMap(); for (String key : propertyMap.keySet()) { MetaDataProperty metadata = propertyMap.get(key); if ((metadata != null) && (metadata.getGroupId() == groupId)) { groupPropertyMap.put(new Integer(metadata.getIndex()), metadata); } } return groupPropertyMap; } /** * Read the options from an XMLProperties object and store in memory. * * @param metadataProperties * an XMLProperties object holding the metadata information. */ public synchronized void load(XMLProperties metadataProperties) throws TransformerException{ // populate the group information String[] groupArray = metadataProperties.getProperty("/metadataConfig/group"); MetaDataGroup defaultGroup = new MetaDataGroup(); defaultGroup.setIndex(0); defaultGroup.setName("Hidden Group"); defaultGroup.setComment("Group for hidden values"); defaultGroup.setDescription("This group holds values that will not show up on the " + "configuration page, but we want to be persisted to backup properties."); groupMap.put(0, defaultGroup); for (int i = 1; i <= groupArray.length; i++ ) { String xPathPrefix = "/metadataConfig/group[" + i + "]"; String[] indexArray = metadataProperties.getProperty(xPathPrefix + "/index"); String[] nameArray = metadataProperties.getProperty(xPathPrefix + "/name"); String[] commentArray = metadataProperties.getProperty(xPathPrefix + "/comment"); String[] descriptionArray = metadataProperties.getProperty(xPathPrefix + "/description"); String[] helpFileArray = metadataProperties.getProperty(xPathPrefix + "/helpFile"); if (indexArray == null || nameArray == null) { throw new TransformerException("PropertiesMetaData.load - Could not process a metadata group properties " + "record. One of the following values is null: name or index"); } Integer intIndex; try { intIndex = Integer.parseInt(indexArray[0]); } catch (NumberFormatException nfe) { throw new TransformerException("PropertiesMetaData.load - Could not process a metadata properties record. " + "index was not a valid integer for group: " + nameArray[0]); } MetaDataGroup group = new MetaDataGroup(); group.setIndex(intIndex); group.setName(nameArray[0]); if (commentArray != null) { group.setComment(commentArray[0]); } if (descriptionArray != null) { group.setDescription(descriptionArray[0]); } if (helpFileArray != null) { group.setHelpFile(helpFileArray[0]); } groupMap.put(intIndex, group); } // populate the property information String[] configArray = metadataProperties.getProperty("/metadataConfig/config"); int configArrayLength = 0; if (configArray != null) { configArrayLength = configArray.length; } for (int i = 1; i <= configArrayLength; i++) { String xPathPrefix = "/metadataConfig/config[" + i + "]"; String[] keyArray = metadataProperties.getProperty(xPathPrefix + "/key"); String[] labelArray = metadataProperties.getProperty(xPathPrefix + "/label"); String[] groupIdArray = metadataProperties.getProperty(xPathPrefix + "/group"); String[] indexArray = metadataProperties.getProperty(xPathPrefix + "/index"); String[] descriptionArray = metadataProperties.getProperty(xPathPrefix + "/description"); String[] helpFileArray = metadataProperties.getProperty(xPathPrefix + "/helpFile"); String[] fieldTypeArray = metadataProperties.getProperty(xPathPrefix + "/fieldType"); String[] isRequired = metadataProperties.getProperty(xPathPrefix + "/required"); if (keyArray == null || labelArray == null || groupIdArray == null || indexArray == null) { throw new TransformerException("PropertiesMetaData.load - Could not process a metadata properties +" + "record. One of the following values is null: key, label, group or index"); } Integer intIndex; Integer intGroupId; try { intIndex = Integer.parseInt(indexArray[0]); intGroupId = Integer.parseInt(groupIdArray[0]); } catch (NumberFormatException nfe) { throw new TransformerException("Could not process a metadata properties record. " + "index was not a valid integer for key: " + keyArray[0] + " : " + nfe.getMessage()); } MetaDataProperty metadata = new MetaDataProperty(); metadata.setKey(keyArray[0]); metadata.setLabel(labelArray[0]); metadata.setGroupId(intGroupId); metadata.setIndex(intIndex); if (descriptionArray != null) { metadata.setDescription(descriptionArray[0]); } if (helpFileArray != null) { metadata.setHelpFile(helpFileArray[0]); } try { if (fieldTypeArray != null) { metadata.setFieldType(fieldTypeArray[0]); Vector fieldOptionNames = new Vector(); Vector fieldOptionValues = new Vector(); if (fieldTypeArray[0].equals("select")) { String[] optionArray = metadataProperties.getProperty(xPathPrefix + "/option"); for (int j = 1; j <= optionArray.length; j++) { String[] fieldOptionArray = metadataProperties.getProperty(xPathPrefix + "/option[" + j + "]/name"); String[] fieldValueArray = metadataProperties.getProperty(xPathPrefix + "/option[" + j + "]/value"); if (fieldOptionArray == null || fieldValueArray == null) { throw new TransformerException("PropertiesMetaData.load - Both name and value must be specified for " + "metadata element: "); } fieldOptionNames.add(fieldOptionArray[0]); fieldOptionValues.add(fieldValueArray[0]); } } metadata.setFieldOptionNames(fieldOptionNames); metadata.setFieldOptionValues(fieldOptionValues); } else { metadata.setFieldType("text"); } } catch (GeneralPropertyException gpe) { throw new TransformerException("PropertiesMetaData.load - Property error while processing key: " + keyArray[0] + " : " + gpe.getMessage()); } if (isRequired != null && isRequired[0].equals("true")) { metadata.setIsRequired(true); } propertyMap.put(keyArray[0], metadata); } } }