package com.yahoo.dtf.config; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.io.PrintStream; import java.io.PrintWriter; import java.io.Reader; import java.io.Writer; import java.util.Collection; import java.util.Enumeration; import java.util.InvalidPropertiesFormatException; import java.util.Iterator; import java.util.Map; import java.util.Set; import java.util.TreeMap; import com.yahoo.dtf.util.PeekableIterator; /** * To make property cloning more efficient between parent threads and children * threads this class will use an array of previous copies to keep track of * all of the properties ever created while making sure only to write a property * to the latest generations position in the array. Basically this is how that * will work: * * Thread1: Properties:{[a=b,b=c]} * * Thread 1 creates 2 underlying threads which now have the following: * Thread2: Properties:{[a=b,b=c],[]} * Thread3: Properties:{[a=b,b=c],[]} * * When Thread2 writes to a property, z then it would do so in its last array * of Properties, like so: * * Thread2: Properties:{[a=b,b=c],[z=d]} * * With this the lookup for z would find it in the latest generation of * properties while the lookup for b would have to go one generation back. * * With this approach the older generation of properties remain unaltered by * secondary threads while allowing those secondary threads to see all of the * properties created as intended. * * @author rlgomes */ public class Properties extends java.util.Properties { private final static Object REMOVED = new Object(); private TreeMap<Object, Object>[] props = null; // used to avoid the props[props.length-1] array lookup ;) private TreeMap<Object, Object> writeprops = null; public Properties() { props = new TreeMap[1]; props[0] = new TreeMap<Object, Object>(); writeprops = props[0]; } public Properties(TreeMap<Object,Object>[] props) { this.props = props; this.writeprops = props[props.length-1]; } @Override public synchronized int size() { int size = 0; for(int i = 0; i < props.length-1; i ++) size += props[i].size(); return size; } @Override public synchronized Object put(Object key, Object value) { // all writes go to the latest generation return writeprops.put(key, value); } @Override public synchronized Object remove(Object key) { Object result = null; for (int i = props.length-1; i >= 0; i--) { if ( (result = props[i].get(key)) != null ) break; } // mark as REMOVED so we don't look it up in a previous generation writeprops.put(key, REMOVED); return result; } @Override public synchronized String getProperty(String key) { for (int i = props.length-1; i >= 0; i--) { String result = props[i].get(key).toString(); if ( result == REMOVED ) return null; if ( result != null ) return result; } return null; } @Override public synchronized Object get(Object key) { for (int i = props.length-1; i >= 0; i--) { Object value = props[i].get(key); if ( value == REMOVED ) return null; if ( value != null ) return value; } return null; } @Override public synchronized Object clone() { TreeMap<Object,Object>[] props = new TreeMap[this.props.length+1]; System.arraycopy(this.props, 0, props, 0, this.props.length); props[props.length-1] = new TreeMap<Object, Object>(); Properties properties = new Properties(props); return properties; } @Override public synchronized boolean containsKey(Object key) { if ( writeprops.get(key) == REMOVED ) return false; for (int i = props.length-1; i >= 0; i--) { if ( props[i].containsKey(key) ) return true; } return false; } @Override public synchronized Enumeration<Object> keys() { final PeekableIterator<Object>[] fenums = new PeekableIterator[props.length]; for (int i = 0; i < props.length; i++) { Iterator<Object> iter = props[i].keySet().iterator(); fenums[i] = new PeekableIterator<Object>(iter); } return new Enumeration<Object>() { PeekableIterator<Object>[] enums = fenums; public boolean hasMoreElements() { for (int i = 0; i < enums.length; i++) { if ( enums[i].hasNext() ) return true; } return false; } public Object nextElement() { String min = null; for (int i = 0; i < enums.length; i++) { if ( enums[i].hasNext() ) { if ( min == null ) { min = enums[i].peek().toString(); } else { String aux = enums[i].peek().toString(); if ( aux.compareTo(min) < 0 ) min = aux; } } } for (int i = 0; i < enums.length; i++) { if ( enums[i].hasNext() && enums[i].peek().equals(min) ) enums[i].remove(); } return min; } }; } /** * @deprecated this method is not allowed. */ @Deprecated @Override public synchronized Enumeration<Object> elements() { throw new RuntimeException("Method not allowed."); } /** * @deprecated this method is not allowed. */ @Deprecated @Override public Set<java.util.Map.Entry<Object, Object>> entrySet() { throw new RuntimeException("Method not allowed."); } /** * @deprecated this method is not allowed. */ @Deprecated @Override public synchronized void clear() { throw new RuntimeException("Method not allowed."); } /** * @deprecated this method is not allowed. */ @Deprecated @Override public synchronized boolean isEmpty() { throw new RuntimeException("Method not allowed."); } /** * @deprecated this method is not allowed. */ @Deprecated @Override public Set<Object> keySet() { throw new RuntimeException("Method not allowed."); } /** * @deprecated this method is not allowed. */ @Deprecated @Override public void list(PrintStream out) { throw new RuntimeException("Method not allowed."); } /** * @deprecated this method is not allowed. */ @Deprecated @Override public void list(PrintWriter out) { throw new RuntimeException("Method not allowed."); } /** * @deprecated this method is not allowed. */ @Deprecated @Override public synchronized void load(InputStream inStream) throws IOException { throw new RuntimeException("Method not allowed."); } /** * @deprecated this method is not allowed. */ @Deprecated public synchronized void load(Reader reader) throws IOException { throw new RuntimeException("Method not allowed."); } /** * @deprecated this method is not allowed. */ @Deprecated @Override public synchronized void loadFromXML(InputStream in) throws IOException, InvalidPropertiesFormatException { throw new RuntimeException("Method not allowed."); } /** * @deprecated this method is not allowed. */ @Deprecated @Override public Enumeration<?> propertyNames() { throw new RuntimeException("Method not allowed."); } /** * @deprecated this method is not allowed. */ @Deprecated @Override public synchronized void putAll(Map<? extends Object, ? extends Object> t) { throw new RuntimeException("Method not allowed."); } /** * @deprecated this method is not allowed. */ @Deprecated @Override public synchronized void save(OutputStream out, String comments) { throw new RuntimeException("Method not allowed."); } /** * @deprecated this method is not allowed. */ @Deprecated @Override public void store(OutputStream out, String comments) throws IOException { throw new RuntimeException("Method not allowed."); } /** * @deprecated this method is not allowed. */ @Deprecated public void store(Writer writer, String comments) throws IOException { throw new RuntimeException("Method not allowed."); } /** * @deprecated this method is not allowed. */ @Deprecated @Override public synchronized void storeToXML(OutputStream os, String comment) throws IOException { throw new RuntimeException("Method not allowed."); } /** * @deprecated this method is not allowed. */ @Deprecated @Override public synchronized void storeToXML(OutputStream os, String comment, String encoding) throws IOException { throw new RuntimeException("Method not allowed."); } /** * @deprecated this method is not allowed. */ @Deprecated public Set<String> stringPropertyNames() { throw new RuntimeException("Method not allowed."); } /** * @deprecated this method is not allowed. */ @Deprecated @Override public Collection<Object> values() { throw new RuntimeException("Method not allowed."); } /** * @deprecated this method is not allowed. */ @Deprecated @Override public synchronized boolean equals(Object o) { throw new RuntimeException("Method not allowed."); } /** * @deprecated this method is not allowed. */ @Deprecated @Override public synchronized Object setProperty(String key, String value) { throw new RuntimeException("Method not allowed."); } /** * @deprecated this method is not allowed. */ @Deprecated @Override public synchronized boolean contains(Object value) { throw new RuntimeException("Method not allowed."); } /** * @deprecated this method is not allowed. */ @Deprecated @Override public String getProperty(String key, String defaultValue) { throw new RuntimeException("Method not allowed."); } /** * @deprecated this method is not allowed. */ @Deprecated @Override public boolean containsValue(Object value) { throw new RuntimeException("Method not allowed."); } }