001 package org.hackystat.sensor.xmldata.util; 002 003 import java.util.ArrayList; 004 import java.util.Iterator; 005 import java.util.List; 006 import java.util.Set; 007 import java.util.concurrent.ConcurrentHashMap; 008 009 /** 010 * Provides a thread-safe property map implementation for use as the value of 011 * the default 'pMap' field in all Sensor Data. Features of this abstract data 012 * type include: 013 * <ul> 014 * <li> Accepts only Strings as keys and values. 015 * <li> The entire property map can be encoded into a string for SOAP 016 * transmission. 017 * <li> The encoded string can be provided to a constructor to rebuild the 018 * object. 019 * <li> The puts and gets are thread-safe. 020 * </ul> 021 * @author Philip M. Johnson 022 * @version $Id: SensorDataPropertyMap.java,v 1.1.1.1 2005/10/20 23:56:44 023 * johnson Exp $ 024 */ 025 public class SensorDataPropertyMap { 026 027 /** A thread-safe map holding the string property names and values. */ 028 private ConcurrentHashMap<String, String> propertyMap = new ConcurrentHashMap<String, String>(); 029 030 /** 031 * The default public constructor for the SensorDataPropertyMap. 032 */ 033 public SensorDataPropertyMap() { 034 // do nothing. 035 } 036 037 /** The default empty SensorDataPropertyMap String representation. * */ 038 private static String defaultMapString = new SensorDataPropertyMap().encode(); 039 040 /** 041 * Creates a thread-safe plist, initializing it with the contents of 042 * encodedMap. 043 * @param encodedMap A string produced from the encode() method. 044 * @throws Exception If encodedMap is not a legal encoded 045 * SensorDataPropertyMap. 046 */ 047 public SensorDataPropertyMap(String encodedMap) throws Exception { 048 try { 049 List<String> propertyList = StringListCodec.decode(encodedMap); 050 for (Iterator<String> i = propertyList.iterator(); i.hasNext();) { 051 String propertyName = i.next(); 052 String propertyValue = i.next(); 053 propertyMap.put(propertyName, propertyValue); 054 } 055 } 056 catch (Exception e) { 057 throw new Exception("Error constructing SensorDataPropertyMap", e); 058 } 059 } 060 061 /** 062 * Puts the (name, value) pair into the SensorDataPropertyMap. 063 * @param name The property name string. 064 * @param value The property value string. 065 */ 066 public void put(String name, String value) { 067 this.propertyMap.put(name, value); 068 } 069 070 /** 071 * Gets the property value associated with name, or returns null if not found. 072 * @param name The property name whose value is to be retrieved (if 073 * available). 074 * @return The property value associated with name, or null if not found. 075 */ 076 public String get(String name) { 077 return this.propertyMap.get(name); 078 } 079 080 /** 081 * Returns the property value associated with name, where name is not 082 * case-sensitive. 083 * @param name The case-insensitive property name whose value is to be 084 * retrieved. 085 * @return The property value, or null if no case-insensitive key (name) is 086 * found. 087 */ 088 public String getIgnoreCase(String name) { 089 // Property maps should not have large numbers of elements, so iteration 090 // should be OK. 091 for (String key : this.propertyMap.keySet()) { 092 if (key.equalsIgnoreCase(name)) { 093 return this.propertyMap.get(key); 094 } 095 } 096 return null; 097 } 098 099 /** 100 * Returns a string containing the "runTime" attribute, or null if not found. 101 * Since there has been confusion involving the spelling of this attribute, 102 * this method tries both "runTime" and "runtime". If both attributes are 103 * present (almost surely an error), the value of the runTime version is 104 * returned. 105 * @return A string containing the runTime (or runtime) attribute. 106 */ 107 public String getRunTime() { 108 String runTime = this.propertyMap.get("runTime"); 109 if (runTime == null) { 110 runTime = this.propertyMap.get("runtime"); 111 } 112 return runTime; 113 } 114 115 /** 116 * Returns the property value associated with name, or defaultValue if not 117 * found. 118 * @param name The property name whose value is to be retrieved. 119 * @param defaultValue The defaultValue to be returned if not present. 120 * @return The property value associated with name, or defaultValue if not 121 * found. 122 */ 123 public String get(String name, String defaultValue) { 124 String value = get(name); 125 return (value == null) ? defaultValue : value; 126 } 127 128 /** 129 * Encodes the contents of this PropertyMap into a String that can be 130 * persisted or transmitted using Soap. Throws a RuntimeException if an error 131 * occurs during encoding, which should be extremely rare. 132 * @return An encoded string. 133 */ 134 public String encode() { 135 ArrayList<String> propertyList = new ArrayList<String>(this.propertyMap.size() * 2); 136 for (String name : this.propertyMap.keySet()) { 137 String value = this.propertyMap.get(name); 138 propertyList.add(name); 139 propertyList.add(value); 140 } 141 String encodedString; 142 try { 143 encodedString = StringListCodec.encode(propertyList); 144 } 145 catch (Exception e) { 146 throw new RuntimeException("Problems encoding the property map string", e); 147 } 148 return encodedString; 149 } 150 151 /** 152 * Returns the contents of the property map in its encoded form. This is 153 * required for sensor data transmission to occur correctly. 154 * @return The contents of the property map in its encoded form. 155 */ 156 @Override 157 public String toString() { 158 // return this.propertyMap.toString(); 159 return this.encode(); 160 } 161 162 /** 163 * Returns the contents of the property map in human readable form. 164 * @return The property map in human readable form. 165 */ 166 public String formattedString() { 167 return this.propertyMap.toString(); 168 } 169 170 /** 171 * Returns a set containing the keys associated with this property map. 172 * @return The keyset. 173 */ 174 public Set<String> keySet() { 175 return this.propertyMap.keySet(); 176 } 177 178 /** 179 * Returns a new SensorDataPropertyMap instance generated from the encoded 180 * String. This method supplied for use as the Converter method in the SDT 181 * definition. 182 * @param encodedMap The encoded version of a SensorDataPropertyMap. 183 * @return A new SensorDataPropertyMap instance. 184 * @throws Exception If problems occur decoding the encoded string. 185 */ 186 public static SensorDataPropertyMap getMap(String encodedMap) throws Exception { 187 return new SensorDataPropertyMap(encodedMap); 188 } 189 190 /** 191 * Returns a new String representation of an empty SensorDataPropertyMap 192 * instance. This method supplied for use as the Defaulter method in the SDT 193 * definition. 194 * @return A new String encoding of an empty SensorDataPropertyMap instance. 195 */ 196 public static String getDefaultMapString() { 197 return defaultMapString; 198 } 199 200 }