* <p>This class is not thread-safe; concurrent access to instances of this
* class must be synchronized.</p>
*
+ * <p>While this class is roughly HashMap<Long,CustomProperty>, that's the
+ * internal representation. To external calls, it should appear as
+ * HashMap<String,Object> mapping between Names and Custom Property Values.</p>
+ *
* @author Rainer Klute <a
* href="mailto:klute@rainer-klute.de"><klute@rainer-klute.de></a>
*/
-public class CustomProperties extends HashMap
+@SuppressWarnings("serial")
+public class CustomProperties extends HashMap<Object,CustomProperty>
{
/**
* <p>Maps property IDs to property names.</p>
*/
- private Map dictionaryIDToName = new HashMap();
+ private Map<Long,String> dictionaryIDToName = new HashMap<Long,String>();
/**
* <p>Maps property names to property IDs.</p>
*/
- private Map dictionaryNameToID = new HashMap();
+ private Map<String,Long> dictionaryNameToID = new HashMap<String,Long>();
/**
* <p>Tells whether this object is pure or not.</p>
private boolean isPure = true;
-
/**
* <p>Puts a {@link CustomProperty} into this map. It is assumed that the
* {@link CustomProperty} already has a valid ID. Otherwise use
* {@link #put(CustomProperty)}.</p>
*/
- public Object put(final Object name, final Object customProperty) throws ClassCastException
+ public CustomProperty put(final String name, final CustomProperty cp)
{
- final CustomProperty cp = (CustomProperty) customProperty;
if (name == null)
{
/* Ignoring a property without a name. */
isPure = false;
return null;
}
- if (!(name instanceof String))
- throw new ClassCastException("The name of a custom property must " +
- "be a java.lang.String, but it is a " +
- name.getClass().getName());
if (!(name.equals(cp.getName())))
throw new IllegalArgumentException("Parameter \"name\" (" + name +
") and custom property's name (" + cp.getName() +
/* Register name and ID in the dictionary. Mapping in both directions is possible. If there is already a */
final Long idKey = Long.valueOf(cp.getID());
- final Object oldID = dictionaryNameToID.get(name);
+ final Long oldID = dictionaryNameToID.get(name);
dictionaryIDToName.remove(oldID);
dictionaryNameToID.put(name, idKey);
dictionaryIDToName.put(idKey, name);
/* Put the custom property into this map. */
- final Object oldCp = super.remove(oldID);
+ final CustomProperty oldCp = super.remove(oldID);
super.put(idKey, cp);
return oldCp;
}
else
{
long max = 1;
- for (final Iterator i = dictionaryIDToName.keySet().iterator(); i.hasNext();)
+ for (final Iterator<Long> i = dictionaryIDToName.keySet().iterator(); i.hasNext();)
{
- final long id = ((Long) i.next()).longValue();
+ final long id = i.next().longValue();
if (id > max)
max = id;
}
/**
* Returns a set of all the names of our
- * custom properties
+ * custom properties. Equivalent to
+ * {@link #nameSet()}
*/
public Set keySet() {
return dictionaryNameToID.keySet();
}
+ /**
+ * Returns a set of all the names of our
+ * custom properties
+ */
+ public Set<String> nameSet() {
+ return dictionaryNameToID.keySet();
+ }
+
+ /**
+ * Returns a set of all the IDs of our
+ * custom properties
+ */
+ public Set<String> idSet() {
+ return dictionaryNameToID.keySet();
+ }
/**
*
* @return the dictionary.
*/
- Map getDictionary()
+ Map<Long,String> getDictionary()
{
return dictionaryIDToName;
}
-
/**
+ * Checks against both String Name and Long ID
+ */
+ public boolean containsKey(Object key) {
+ if(key instanceof Long) {
+ return super.containsKey((Long)key);
+ }
+ if(key instanceof String) {
+ return super.containsKey((Long)dictionaryNameToID.get(key));
+ }
+ return false;
+ }
+
+ /**
+ * Checks against both the property, and its values.
+ */
+ public boolean containsValue(Object value) {
+ if(value instanceof CustomProperty) {
+ return super.containsValue((CustomProperty)value);
+ } else {
+ for(CustomProperty cp : super.values()) {
+ if(cp.getValue() == value) {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
+
+
+ /**
* <p>Gets the codepage.</p>
*
* @return the codepage or -1 if the codepage is undefined.
public int getCodepage()
{
int codepage = -1;
- for (final Iterator i = this.values().iterator(); codepage == -1 && i.hasNext();)
+ for (final Iterator<CustomProperty> i = this.values().iterator(); codepage == -1 && i.hasNext();)
{
- final CustomProperty cp = (CustomProperty) i.next();
+ final CustomProperty cp = i.next();
if (cp.getID() == PropertyIDMap.PID_CODEPAGE)
codepage = ((Integer) cp.getValue()).intValue();
}
{
cps = new CustomProperties();
final Section section = (Section) getSections().get(1);
- final Map dictionary = section.getDictionary();
+ final Map<Long,String> dictionary = section.getDictionary();
final Property[] properties = section.getProperties();
int propertyCount = 0;
for (int i = 0; i < properties.length; i++)
{
propertyCount++;
final CustomProperty cp = new CustomProperty(p,
- (String) dictionary.get(Long.valueOf(id)));
+ dictionary.get(Long.valueOf(id)));
cps.put(cp.getName(), cp);
}
}
{
ensureSection2();
final MutableSection section = (MutableSection) getSections().get(1);
- final Map dictionary = customProperties.getDictionary();
+ final Map<Long,String> dictionary = customProperties.getDictionary();
section.clear();
/* Set the codepage. If both custom properties and section have a
customProperties.setCodepage(cpCodepage);
section.setCodepage(cpCodepage);
section.setDictionary(dictionary);
- for (final Iterator i = customProperties.values().iterator(); i.hasNext();)
+ for (final Iterator<CustomProperty> i = customProperties.values().iterator(); i.hasNext();)
{
- final Property p = (Property) i.next();
+ final Property p = i.next();
section.setProperty(p);
}
}
* decision has been taken when specifying the "properties" field
* as an Property[]. It should have been a {@link java.util.List}.</p>
*/
- private List preprops;
+ private List<Property> preprops;
dirty = true;
formatID = null;
offset = -1;
- preprops = new LinkedList();
+ preprops = new LinkedList<Property>();
}
public void setProperties(final Property[] properties)
{
this.properties = properties;
- preprops = new LinkedList();
+ preprops = new LinkedList<Property>();
for (int i = 0; i < properties.length; i++)
preprops.add(properties[i]);
dirty = true;
*/
public void removeProperty(final long id)
{
- for (final Iterator i = preprops.iterator(); i.hasNext();)
- if (((Property) i.next()).getID() == id)
+ for (final Iterator<Property> i = preprops.iterator(); i.hasNext();)
+ if (i.next().getID() == id)
{
i.remove();
break;
}
/* Sort the property list by their property IDs: */
- Collections.sort(preprops, new Comparator()
+ Collections.sort(preprops, new Comparator<Property>()
{
- public int compare(final Object o1, final Object o2)
+ public int compare(final Property p1, final Property p2)
{
- final Property p1 = (Property) o1;
- final Property p2 = (Property) o2;
if (p1.getID() < p2.getID())
return -1;
else if (p1.getID() == p2.getID())
/* Write the properties and the property list into their respective
* streams: */
- for (final ListIterator i = preprops.listIterator(); i.hasNext();)
+ for (final ListIterator<Property> i = preprops.listIterator(); i.hasNext();)
{
final MutableProperty p = (MutableProperty) i.next();
final long id = p.getID();
* @exception IOException if an I/O exception occurs.
*/
private static int writeDictionary(final OutputStream out,
- final Map dictionary, final int codepage)
+ final Map<Long,String> dictionary, final int codepage)
throws IOException
{
int length = TypeWriter.writeUIntToStream(out, dictionary.size());
- for (final Iterator i = dictionary.keySet().iterator(); i.hasNext();)
+ for (final Iterator<Long> i = dictionary.keySet().iterator(); i.hasNext();)
{
- final Long key = (Long) i.next();
- final String value = (String) dictionary.get(key);
+ final Long key = i.next();
+ final String value = dictionary.get(key);
if (codepage == Constants.CP_UNICODE)
{
*
* @see Section#getDictionary()
*/
- public void setDictionary(final Map dictionary)
+ public void setDictionary(final Map<Long,String> dictionary)
throws IllegalPropertySetDataException
{
if (dictionary != null)
{
- for (final Iterator i = dictionary.keySet().iterator();
- i.hasNext();)
- if (!(i.next() instanceof Long))
- throw new IllegalPropertySetDataException
- ("Dictionary keys must be of type Long.");
- for (final Iterator i = dictionary.values().iterator();
- i.hasNext();)
- if (!(i.next() instanceof String))
- throw new IllegalPropertySetDataException
- ("Dictionary values must be of type String.");
this.dictionary = dictionary;
/* Set the dictionary property (ID 0). Please note that the second
* <p>Maps property IDs to section-private PID strings. These
* strings can be found in the property with ID 0.</p>
*/
- protected Map dictionary;
+ protected Map<Long,String> dictionary;
/**
* <p>The section's format ID, {@link #getFormatID}.</p>
/* Look for the codepage. */
int codepage = -1;
- for (final Iterator i = propertyList.iterator();
+ for (final Iterator<PropertyListEntry> i = propertyList.iterator();
codepage == -1 && i.hasNext();)
{
- ple = (PropertyListEntry) i.next();
+ ple = i.next();
/* Read the codepage if the property ID is 1. */
if (ple.id == PropertyIDMap.PID_CODEPAGE)
/* Pass 2: Read all properties - including the codepage property,
* if available. */
int i1 = 0;
- for (final Iterator i = propertyList.iterator(); i.hasNext();)
+ for (final Iterator<PropertyListEntry> i = propertyList.iterator(); i.hasNext();)
{
- ple = (PropertyListEntry) i.next();
+ ple = i.next();
Property p = new Property(ple.id, src,
this.offset + ple.offset,
ple.length, codepage);
* <p>Represents an entry in the property list and holds a property's ID and
* its offset from the section's beginning.</p>
*/
- class PropertyListEntry implements Comparable
+ class PropertyListEntry implements Comparable<PropertyListEntry>
{
int id;
int offset;
*
* @see Comparable#compareTo(java.lang.Object)
*/
- public int compareTo(final Object o)
+ public int compareTo(final PropertyListEntry o)
{
- if (!(o instanceof PropertyListEntry))
- throw new ClassCastException(o.toString());
- final int otherOffset = ((PropertyListEntry) o).offset;
+ final int otherOffset = o.offset;
if (offset < otherOffset)
return -1;
else if (offset == otherOffset)
* @return the dictionary or <code>null</code> if the section does not have
* a dictionary.
*/
- public Map getDictionary()
+ public Map<Long,String> getDictionary()
{
return dictionary;
}
// Now custom ones
CustomProperties cps = dsi == null ? null : dsi.getCustomProperties();
if(cps != null) {
- Iterator keys = cps.keySet().iterator();
+ Iterator<String> keys = cps.nameSet().iterator();
while(keys.hasNext()) {
- String key = (String)keys.next();
+ String key = keys.next();
String val = getPropertyValueText( cps.get(key) );
text.append(key + " = " + val + "\n");
}
customProperties.put("min_Long", MIN_LONG);
customProperties.put("max_Double", MAX_DOUBLE);
customProperties.put("min_Double", MIN_DOUBLE);
+
+ // Check the keys went in
+ assertTrue(customProperties.containsKey("Schl\u00fcssel \u00e4"));
+ assertTrue(customProperties.containsKey("Boolean"));
+
+ // Check the values went in
+ assertEquals("Wert \u00e4", customProperties.get("Schl\u00fcssel \u00e4"));
+ assertEquals(Boolean.TRUE, customProperties.get("Boolean"));
+ assertTrue(customProperties.containsValue(Boolean.TRUE));
+ assertTrue(customProperties.containsValue("Wert \u00e4"));
+
+ // Check that things that aren't in aren't in
+ assertFalse(customProperties.containsKey("False Boolean"));
+ assertFalse(customProperties.containsValue(Boolean.FALSE));
+
+ // Save as our custom properties
dsi.setCustomProperties(customProperties);
+
/* Write the summary information stream and the document summary
* information stream to the POI filesystem. */
si.write(dir, siEntry.getName());